The dacite docs have a section about nested structures that is very close to what you want. The example they use, verbatim, is as follows:
@dataclass
class A:
    x: str
    y: int
@dataclass
class B:
    a: A
data = {
    'a': {
        'x': 'test',
        'y': 1,
    }
}
result = from_dict(data_class=B, data=data)
assert result == B(a=A(x='test', y=1))
We can access fields at arbitrary depth as e.g. result.a.x == 'test'.
The critical difference between this and your data is that the dictionary under the data key has keys with arbitrary values (Aatrox, Ahri, etc.). dacite isn't set up to create new field names on the fly, so the best you're going to get is something like the latter part of @JonSG's answer, which uses setattr to dynamically build new fields.
Let's imagine how you would use this data for a moment, though. Probably you'd want a some point to be able to iterate over your champions in order to perform a filter/transform/etc. operation. It's possible to iterate over fields in python, but you have to really dig into python internals, which means your code will be less readable/generally comprehensible.
Much better would be one of the following:
- Preprocess j1into a shape that fits the structure you want to use, and then use dacite with adataclassthat fits the new structure. For example, maybe it makes sense to pull the values of thedatadict out into a list.
- Process in steps using dacite. For example, something like the following:
from dataclasses import dataclass
from dacite import from_dict
@dataclass
class TopLevel:
    type: str
    data: dict
j1 = {
    "type": "champion",
    "data": {
        "Aatrox": {"id": "Aatrox", "key": "266", "name": "Aatrox"},
        "Ahri": {"id": "Ahri", "key": "103", "name": "Ahri"},
    },
}
champions = from_dict(data_class=TopLevel, data=j1)
# champions.data is a dict of dicts
@dataclass
class Champion:
    id: str
    key: str
    name: str
# transform champions.data into a dict of Champions
for k, v in champions.data.items():
    champions.data[k] = from_dict(data_class=Champion, data=v)
# now, you can do interesting things like the following filter operation
start_with_a = [
    champ for champ in champions.data.values() if champ.name.lower().startswith("a")
]
print(start_with_a)
# [Champion(id='Aatrox', key='266', name='Aatrox'), Champion(id='Ahri', key='103', name='Ahri')]