If your IQueryProvider supports casting projected instances to a base Type, you can project to derived Types via configured conditions. For example:

// Using an EF Core DbContext:
var animalDtos = await context
    .Animals
    .ProjectTo<AnimalDto>(cfg => cfg
        .If(a => a.Type == AnimalType.Dog)
        .MapTo<DogDto>()
        .And
        .If(a => a.Type == AnimalType.Cat)
        .MapTo<CatDto>()
        .And
        .If(a => a.Type == AnimalType.Gorilla)
        .MapTo<GorillaDto>())
    .ToArrayAsync();

A query projection will be generated which creates the appropriate derived Type for the AnimalType. If the Animal.Type does not match a configured value, an AnimalDto is created. If AnimalDto is abstract, the Animal is projected to null.