I'd recommend using a combination of TypeVar, to indicate that your self.o value could be any arbitrary type, and Type, in the following way:
from typing import TypeVar, Type T = TypeVar('T') class MyObj: def __init__(self, o: T) -> None: self.o = o def get_obj_class(self) -> Type[T]: return type(self.o) def accept_int_class(x: Type[int]) -> None: pass i = MyObj(3) foo = i.get_obj_class() accept_int_class(foo) # Passes s = MyObj("foo") bar = s.get_obj_class() accept_int_class(bar) # Fails
If you want the type of o to be even more dynamic, you could explicitly or implicitly give it a type of Any.
Regarding your latter question, you'd do:
def f(cls: Type[T]) -> T: return cls()
Note that you need to be careful when instantiating your class -- I don't remember what Pycharm does here, but I do know that mypy currently does not check to make sure you're calling your __init__ function correctly/with the right number of params.
(This is because T could be anything, but there's no way to hint what the constructor ought to look like, so performing this check would end up being either impossibly or highly difficult.)