Should one interface inherit another interface
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
Yes, one interface can and often should inherit another interface, but only when the derived interface is truly a more specific contract. Interface inheritance is a modeling tool, not a convenience feature. If the relationship is weak or accidental, it usually creates unnecessary coupling and pushes unrelated methods onto implementers.
When Interface Inheritance Makes Sense
A good rule is simple: if every implementation of the child interface must also satisfy the parent interface, inheritance is appropriate.
A classic example is a readable stream and a seekable readable stream:
This models a clear subtype relationship. Anything that is a SeekableReader is also a Reader, so code that only needs Reader can accept the more specific type without knowing about seeking.
That gives you two benefits:
- shared vocabulary for the common contract
- stronger type information for specialized consumers
For example:
This is exactly what interfaces are good at: expressing behavior in layers of increasing specificity.
When It Is a Design Smell
The trouble starts when an interface inherits another one merely to avoid repetition or to force unrelated capabilities together.
Suppose you write this:
That design says every cache is also a logger. That is rarely true. Logging may be a feature of one implementation, but it is not a defining part of what a cache is. The inheritance expresses the wrong semantic relationship.
In cases like that, keep the contracts separate:
A class can still implement both interfaces when needed, but the type system no longer lies about the domain model.
Favor Small, Focused Contracts
This idea lines up with the Interface Segregation Principle. Small interfaces are easier to compose than large inherited hierarchies.
In C#, for example:
Here the class composes several focused capabilities without needing an artificial inheritance chain between the interfaces. That tends to stay flexible as the system evolves.
A Useful Decision Test
Before making one interface extend another, ask:
- Is the child always a valid substitute for the parent
- Would every implementation of the child naturally support every member of the parent
- Does the inheritance communicate domain meaning, not just code reuse
If the answer to any of these is no, composition is usually better than inheritance.
Versioning and API Stability
Interface inheritance also affects public API evolution. If you publish a base interface and many implementations depend on it, adding members to that base can ripple across your codebase or external consumers.
That means inheritance should be used carefully in shared libraries. A narrow base contract stays stable longer. A deep hierarchy can make even small changes expensive.
Sometimes it is safer to add a new sibling interface than to expand an inherited base contract. That lets callers opt into new behavior without breaking existing implementers.
Common Pitfalls
The biggest pitfall is inheriting for convenience instead of semantics. Removing duplicated method signatures feels nice in the moment, but the result can encode a false subtype relationship.
Another issue is building deep interface hierarchies too early. A couple of levels may be reasonable, but large inheritance trees make it harder to understand what a type actually promises.
Developers also sometimes use inheritance when multiple interface implementation would be clearer. If a class can read and write, that does not automatically mean Writable should extend Readable or the other way around.
Finally, think about consumers, not just implementers. If most callers only need a tiny contract, exposing a large inherited interface makes testing and substitution harder than necessary.
Summary
- An interface should inherit another interface only when it represents a true subtype.
- Inheritance is appropriate for specialization, not just for avoiding repeated method signatures.
- Separate interfaces and multiple implementation are often better for unrelated capabilities.
- Small, focused contracts usually age better than deep interface hierarchies.
- If the domain meaning is unclear, prefer composition over interface inheritance.
Related reading
- Should the Domain ever access Application Services of another system?
- Simple way for message passing in distributed system
- Simulating 2 phase distributed commit failures using grpc
- Singleton/Synchronization in Clustered environment
- Singleton by Jon Skeet clarification
- Singleton with Arguments in Java
- Slow Performance with Apache Spark Gradient Boosted Tree training runs
- Smart pagination algorithm that works with local data cache

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.