---
title: "Keep the contract in every subtype · Agent Wranglers"
url: https://agentwranglers.se/playbook/architecture/solid-and-dry/liskov-substitution
updated: 2026-10-20
licence: "All rights reserved"
---

# Keep the contract in every subtype

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [SOLID and DRY](https://agentwranglers.se/playbook/architecture/solid-and-dry)
- Rule: A subtype must work everywhere its parent type works. It may not demand more, promise less or throw "not supported".
- How: Before you extend a class, list what callers rely on. If the subtype cannot keep all of it, use a separate type or a smaller interface instead. Never override a method only to throw.
- Check: Run the parent type's tests against every subtype. A grep for `NotImplemented` or "not supported" in overriding methods fails the build.

Example:

```ts
// Bad: callers of Storage break on the read-only subtype
class ReadOnlyStorage extends Storage {
  save(): void { throw new Error('not supported'); }
}

// Good: separate the roles, so nothing has to refuse
interface Reader { load(key: string): string; }
interface Writer { save(key: string, value: string): void; }
```

```python
# Good in Python: two small protocols, so nothing has to refuse
class Reader(Protocol):
    def load(self, key: str) -> str: ...

class Writer(Protocol):
    def save(self, key: str, value: str) -> None: ...
```

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers architecture playbook: https://agentwranglers.se/playbook/architecture/solid-and-dry/liskov-substitution`.

- Previous: [Extend code without editing it](https://agentwranglers.se/playbook/architecture/solid-and-dry/open-closed)
- Next: [Prefer composition over inheritance](https://agentwranglers.se/playbook/architecture/solid-and-dry/composition-over-inheritance)
- [SOLID and DRY](https://agentwranglers.se/playbook/architecture/solid-and-dry)
