In general we want to satisfy substitutability: if B is a subclass of A, anywhere we expect an instance of A we can use an instance of B.
Inheritance gets used for a number of purposes in typical object-oriented programming:
specification -- the superclass just specifies which methods should be available but doesn't give code. This is supported in java by interfaces and abstract methods.
construction -- the superclass is just used to provide behavior, but instances of the subclass don't really act like the superclass. Violates substitutability. Exmample: defining Stack as a subclass of Vector. This is not clean -- better to define Stack as having a field that holds a vector.
extension -- subclass adds new methods, and perhaps redefines inherited ones as well.
limitation -- the subclass restricts the inherited behavior. Violates substitutability. Example: defining Queue as a subclass of Dequeue.
combination -- multiple inheritance. Provided in part by implementing multiple interfaces.