dotnet/efcore · error · InvalidOperationException

The element type of the result of

Error message

The element type of the result of '{dbFunction}' is mapped to '{entityType}'. This is not supported since '{entityType}' is part of hierarchy but does not contain a discriminator property. Only TPH hierarchies can be mapped to a TVF.

What it means

Thrown when a DbFunction (TVF) returns an IQueryable<T> whose entity type is part of an inheritance hierarchy but has no discriminator property. EF only supports mapping a TVF to a TPH (table-per-hierarchy) hierarchy, because a TVF produces a single rowset. The check at RelationalModelValidator.cs:394-399 requires FindDiscriminatorProperty() to be non-null whenever the type has a BaseType or derived types.

Solutions

  1. Remove the DbFunction/TVF mapping for hierarchies that are not TPH — TVFs require TPH.
  2. If TPH is acceptable, configure the hierarchy as TPH and add a discriminator: modelBuilder.Entity<Base>().HasDiscriminator<string>("Discriminator").HasValue<Base>("base").HasValue<Derived>("derived").
  3. Split the TVF into per-type queries (FromSqlRaw / regular LINQ) instead of a single IQueryable<Base> TVF.
  4. Make the TVF return a flat keyless DTO entity outside the hierarchy and project into it.

Example fix

// before — hierarchy is TPT, no discriminator
modelBuilder.Entity<Person>().UseTptMappingStrategy();
modelBuilder.Entity<Employee> : Person
public IQueryable<Person> ActivePeople()
    => FromExpression(() => ActivePeople());
// throws TableValuedFunctionNonTph

// after — TVF over TPH hierarchy
modelBuilder.Entity<Person>()
    .HasDiscriminator<string>("PersonType")
    .HasValue<Customer>("customer")
    .HasValue<Employee>("employee");
Defensive patterns

Strategy: validation

Validate before calling

// Verify any TVF return type, if in a hierarchy, has a discriminator.
foreach (var dbFn in modelBuilder.Model.GetDbFunctions())
{
    if (dbFn.IsScalar) continue;
    var elementType = dbFn.ReturnType.GetGenericArguments()[0];
    var et = modelBuilder.Model.FindEntityType(elementType);
    if (et is null) continue;
    if ((et.BaseType is not null || et.GetDerivedTypes().Any())
        && et.FindDiscriminatorProperty() is null)
    {
        throw new InvalidOperationException($"Hierarchy root '{et.Name}' used by TVF '{dbFn.Name}' must be TPH with a discriminator.");
    }
}

Try / catch

try { _ = ctx.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("Only TPH hierarchies can be mapped to a TVF"))
{
    logger.LogError("TVF mapping requires TPH; switch hierarchy or remove TVF. {Msg}", ex.Message);
    throw;
}

Prevention

When it happens

Trigger: Defining a DbFunction returning IQueryable<BaseEntity> where BaseEntity is abstract or has derived types, while the hierarchy is mapped TPT or TPC (no discriminator). Also triggered if you forgot HasDiscriminator() on a base type that should be TPH.

Common situations: Switching an inheritance hierarchy from TPH to TPT/Tpc via UseTptMappingStrategy()/UseTpcMappingStrategy() without removing existing TVF mappings; using TVFs on hierarchies introduced after EF7's TPT/Tpc support; remapping an owned hierarchy.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/8b4c7347a7ce1ea8. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:397

                || ((IConventionModel)model).IsOwned(elementType)
                || (entityType == null && model.GetEntityTypes().Any(e => e.ClrType == elementType)))
            {
                throw new InvalidOperationException(
                    RelationalStrings.DbFunctionInvalidIQueryableOwnedReturnType(
                        dbFunction.ModelName, elementType.ShortDisplayName()));
            }

            if (entityType == null)
            {
                throw new InvalidOperationException(
                    RelationalStrings.DbFunctionInvalidReturnEntityType(
                        dbFunction.ModelName, dbFunction.ReturnType.ShortDisplayName(), elementType.ShortDisplayName()));
            }

            if ((entityType.BaseType != null || entityType.GetDerivedTypes().Any())
                && entityType.FindDiscriminatorProperty() == null)
            {
                throw new InvalidOperationException(
                    RelationalStrings.TableValuedFunctionNonTph(dbFunction.ModelName, entityType.DisplayName()));
            }
        }

        foreach (var parameter in dbFunction.Parameters)
        {
            if (parameter.TypeMapping == null)
            {
                throw new InvalidOperationException(
                    RelationalStrings.DbFunctionInvalidParameterType(
                        parameter.Name,
                        dbFunction.ModelName,
                        parameter.ClrType.ShortDisplayName()));
            }
        }
    }

    /// <summary>

View on GitHub (pinned to 3a2006ef56)