2026, Jan 01 07:00

Resolving mypy 'Incompatible types' errors in conditional expressions with multiple inheritance

Learn why mypy misreports types for conditional expressions with multiple inheritance and how to fix it. Upgrade to mypy 1.12+ or apply a simple workaround.

Type checking conditional expressions with multiple inheritance can reveal sharp edges. A minimal example that should be straightforward ends up triggering a confusing error about incompatible types, even though both branches share the required base class.

Problem statement

Consider two classes inheriting from the same pair of bases, and a conditional expression where the target type is one of those bases. The assignment below is expected to be valid but may fail under certain mypy versions.

class Core: pass
class Proto: pass
class ImplOne(Core, Proto): pass
class ImplTwo(Core, Proto): pass
switch: bool  # some condition
res: Proto = ImplTwo() if switch else ImplOne()  # mypy error in affected versions

The type checker reports an error similar to “Incompatible types in assignment (expression has type "Core", variable has type "Proto")”.

Why this happens

The issue stems from how older mypy versions handled multiple inheritance within conditional expressions. When both branches are subclasses of two common bases, the checker incorrectly narrows the result to the other base rather than the one you are targeting. In the example above, both branches are valid instances of Proto, but the inferred expression type degrades to Core, causing the assignment to fail.

Workarounds you might attempt

One way to sidestep the error is to pre-assign each branch to a variable already typed as the desired base and only then choose between them. This keeps the overall logic unchanged, but the structure is less elegant.

def pick(use_first: bool):
    left_item: Proto = ImplOne()
    right_item: Proto = ImplTwo()
    chosen: Proto = left_item if use_first else right_item

This pattern mirrors the original intent while making the intermediate types explicit.

The fix

This behavior was a mypy bug present in versions prior to 1.12.0. Upgrading to mypy 1.12 or later restores correct handling of multiple inheritance in this scenario. After the update, the original form type-checks as intended.

class Core: pass
class Proto: pass
class ImplOne(Core, Proto): pass
class ImplTwo(Core, Proto): pass
flag: bool
result: Proto = ImplTwo() if flag else ImplOne()  # correctly handled in mypy 1.12+

Why this matters

Conditional expressions are common in production code, and multiple inheritance is a legitimate, if sparingly used, technique. When a type checker misinforms you about these constructs, it leads to unnecessary refactors, noisy suppressions, or loss of confidence in the tool. Keeping mypy current ensures that the checker reflects the actual semantics of your class relationships and doesn’t block safe patterns.

Conclusion

If you run into an error that claims a conditional expression has type A while your variable expects type B, despite both branches inheriting from A and B, verify your mypy version. Upgrading to 1.12 or newer resolves the incorrect inference. If upgrading is not immediately possible, isolating each branch into variables typed as the intended base can help you move forward without changing runtime behavior.