Question: I suppose how it can be check what type specified on Generic types in __init__ ? On python 3.10, it could not be. On first, I found this page: Instantiate a type that is a TypeVar and make some utility for get __orig_class__. And test on instancing time, there is no __orig_class__ attribute in that timing on self. Then I searched again I found this issue page: https://github.com/python/typing/issues/658. I recognized that any python might have this limit. Is there any other way? The following is sample code (not original one). This code cannot be executed for the reasons stated above. (I haven't run it, so there may be some bugs too.) from abc import ABC, abstractmethod from typing import Iterable, Any, TypeVar, Generic class BaseLoader(ABC): """ `BaseLoader` loads something and return some expected object. - load a file from path(str) - convert a raw data to some expected data (list like) - implement `load` in inherited class. """ def __init__(self, path: str): self._path = path @abstractmethod def load(self) -> Iterable: pass class SimpleLineLoader(BaseLoader): """ `SimpleTextBaseLoader` loads text data and return some converted lines. - load a utf-8 text file. - convert to a list of text lines. - implement `_convert_line` in inherited class. """ def load(self): with open(self._path, "r") as f: lines = f.readlines() converted_lines = [self._convert_line(line) for line in lines] return converted_lines @abstractmethod def _convert_line(self, line: str) -> Any: """ `_convert_line` convert line string to another one. """ pass class RawLineLoader(SimpleLineLoader): """ `RawLineLoader` loads raw data. nothing to do. """ def _convert_line(self, line): """ nothing to do. just return raw value. """ return line class ElementTrimmedLineLoader(SimpleLineLoader): """ `ElementTrimmedLineLoader` loads lines and regards each line as comma(,) separated data. it trims each tokens in the line and get back to the line. - trims each element separated with comma in each line. - sample: >>> from tempfile import TemporaryDirectory >>> data = ["a, b, d ", "d , e , f"] >>> with TemporaryDirectory() as dname: >>> with open(dname, "w") as f: >>> f.writelines(data) >>> loader = ElementTrimmedLineLoader(f.name) >>> print(loader.load()) [['a', 'b', 'd'], ['d', 'e', 'f']] """ def __init__(self, path): super().__init__(path) self._delim = "," def _convert_line(self, line): """ split with the delim and trim each element, combine them to one with the delim again. """ delim = self._delim converted = delim.join(elem.strip(' ') for elem in line.split(delim)) return converted def get_delim(self): """ get a delimiter in use """ return self._delim class BaseProcessor(ABC): """ `BaseProcessor` process `Iterable` and return a list of result of `_process_element`. - implement `_process_element` in inherited class. """ def __init__(self, loader: BaseLoader, another_param: object): self._loader = loader self._another_param = another_param def process(self, elements: Iterable) -> list[Any]: data = self._loader.load() result = [] for element in data: output = self._process_element(element) result.append(output) # print(output) return result @abstractmethod def _process_element(self, element: object) -> Any: pass options = {filename: "c:/some/constant/path.txt"} T = TypeVar(T, bound=BaseLoader) class SimpleBaseProcessor(BaseProcessor, Generic[T]): """ `SimpleBaseProcessor` process a constant file, and return raw values in situ. - indicate `BaseLoader` class. (what data is expected as prerequisite) - override `_process_element` in inherited class. """ def __init__(self, another_param: object): loader_class = self.__orig_class__.__args__[0] loader = loader_class(options["filename"]) super().__init__(loader, another_param) def _process_element(self, element): """ nothing to do. just return raw value. (default) """ return element class LineCountPrefixedProcessor(SimpleBaseProcessor[RawLineLoader]): """ `LineCountPrefixedProcessor` return a list of line count prefixed line strings. """ def __init__(self, another_param, prefix = "{0} | "): super().__init__(another_param) self._prefix = prefix self._count = 0 def _process_element(self, element): processed = self._prefix.format(self._count) + element self._count += 1 return processed class ElementQuoteProcessor(SimpleBaseProcessor[ElementTrimmedLineLoader]): """ `ElementQuoteProcessor` process trimmed elements and quote each of them. """ def __init__(self, another_param, quote_char = "'"): super().__init__(another_param) self._quote_char = quote_char def _quote(self, target): q = self._quote return q + target + q def _process_element(self, element): delim = self._loader.get_delim() return delim.join(self._quote(elem) for elem in element.split(delim)) 

Answer: When you write something like: from typing import Generic, TypeVar T = TypeVar('T') class MyGeneric(Generic[T]): def __init__(self): print(getattr(self, '__orig_class__', None)) x = MyGeneric[int]()  You may see x.orig_class appear on some Python versions and not on others. That is an internal artifact of how the CPython interpreter (and the typing module) tracked Generic information in older versions. It was never specified in any PEP as a stable, user-facing API for “inspect your type parameters at runtime.” Since standard Python discards generic parameters at runtime, why not just store them yourself from typing import Generic, TypeVar, Type T = TypeVar('T') class MyGenericClass(Generic[T]): def __init__(self, t: Type[T]): self._t = t x - MyGenericClass(int) print(x._t)  Or just pass the value class MyGenericClass(Generic[T]): def __init(self, examplevalue: T): self._t = type(examplevalue)