They are not checked at runtime at all. Type declarations are only used for static analyzing tools and not by the runtime.
So types are checked BEFORE runtime by the tooling just like they would be in TypeScript or any other language that offers gradual typing.
Yes, the dynamic nature of Python does make type safety and certain performance optimizations very difficult but then again it is the dynamic nature that allows for the high productivity of the language. A static language would be far less ergonomic to use for the typical prototyping and explorative programming done in Python.