Inheritance is useful in cases where the subclasses benefit from inheriting both implementation and definitions of the superclass, and the system as a whole is simplified (not complicated) by it.
One of the most common usages of Inheritance is for user interface controls. RichTextBox for example contains all the properties, internal fields and methods as a simple TextBox. In addition, it exposes some extra properties which enable richer editing capabilities. Using inheritance in this case makes more sense than any other practice. It reduces code size and code complexity.
Miss-usages of inheritance often result in a tightly coupled and overly complicated code. There are some good practices that help elevating this problem. The use of composition and interfaces instead of inheritance is strongly preferred, and when inheritance is used it’s recommended to keep inheritance graph as shallow as possible to avoid the Yo-yo problem (where the programmer has to keep flipping between classes in order to follow the control flow of the program).
Unfortunately, there’s no simple way to avoid these miss-usages other than through a strict code review process.
Java, C# and other high level languages eliminated the worst ‘feature’ of inheritance: Multiple inheritance. The most notorious problem associated with this feature is the "diamond problem”, which arises when two classes B and C inherit from A, and class D inherits from both B and C.
In addition, the Yo-yo problem is made much worse when Multiple inheritance is used.