Typing a class hierarchy with generics and covarying metadata class

I’m working on typing an old code base that attempts to provide uniform access to data file formats, including versions of the same format. Generally, the data format is a straightforward binary block, and the difference is in the header, so we have a structure File(Header, Data). It would be nice for type checkers to be able to recognize that FileTypeA().header has type HeaderTypeA.

My attempts so far have left me with all file classes having headers that are interpreted as the first concrete type. Below is my approach, boiled down to two versions:

import typing as ty

class Header:

HdrT = ty.TypeVar('HdrT', bound=Header)    

class HeaderWithMetaData(Header):
    metadata: dict[str, str]

    def __init__(self, metadata=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.metadata = {}
        if metadata:

class DataFile(ty.Generic[HdrT]):
    header: HdrT
    header_class: type[HdrT]
    def __init__(self, header=None, data=None):
        self.header = header or self.header_class()

class HeaderV1(Header): 
    magic_number: bytes = b'HDR'
    format_version: int = 1

class DataFileV1(DataFile[HeaderV1]):
    header_class = HeaderV1

class HeaderV2(HeaderV1, HeaderWithMetaData):
    format_version = 2

class DataFileV2(DataFileV1, DataFile[HeaderV2]):
    header_class = HeaderV2

file1 = DataFileV1()
file2 = DataFileV2()

    # Shows HeaderV1, but I would like it to be HeaderV2
    # Acts like HeaderV2

Is what I’m aiming for possible? I haven’t fully wrapped my head around covariants and contravariants, so it’s possible the answer is in that direction, but my playing around there has not landed on something helpful yet.