With this code: from typing import Protocol from sqlalchemy import Integer from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class SpamProt(Protocol): id: int class Base(DeclarativeBase): pass class SpamModel(Base): id: Mapped[int] = mapped_column(Integer()) def do_with_spam(d: SpamProt) -> None: raise NotImplementedError() if __name__ == "__main__": spam = SpamModel(id=10) do_with_spam(spam) mypy is returning an error: spam.py:24: error: Argument 1 to "do_with_spam" has incompatible type "SpamModel"; expected "SpamProt" [arg-type] spam.py:24: note: Following member(s) of "SpamModel" have conflicts: spam.py:24: note: id: expected "int", got "Mapped[int]" Found 1 error in 1 file (checked 1 source file) As SQLAlchemy claims to have no fully compatible typing without any plugins, I don't understand why this simplest example doesn't work. It is not a result of invariance. It is not an effect of interference from old plugin (here's the whole environment): ╭───────────────────┬─────────┬──────────╮ │ name │ version │ location │ ├───────────────────┼─────────┼──────────┤ │ greenlet │ 3.1.1 │ │ │ mypy │ 1.15.0 │ │ │ mypy-extensions │ 1.0.0 │ │ │ SQLAlchemy │ 2.0.39 │ │ │ typing_extensions │ 4.12.2 │ │ ╰───────────────────┴─────────┴──────────╯ do I fundamentally misunderstand how the Mapped arguments should work? Continue reading...