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
- Remove the DbFunction/TVF mapping for hierarchies that are not TPH — TVFs require TPH.
- 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").
- Split the TVF into per-type queries (FromSqlRaw / regular LINQ) instead of a single IQueryable<Base> TVF.
- 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 adopting TPT/Tpc, audit existing DbFunction/TVF mappings and remove or convert them.
- Add HasDiscriminator(...) whenever an entity type participates in a hierarchy used by a TVF.
- Document inheritance strategy per hierarchy in the entity's XML comments.
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
- The derived entity type
- The mapping strategy
- The DbFunction ' ' returns ' ', but ' ' is not a mapped…
- The entity type ' ' is mapped to the 'DbFunction' named '…
- The entity type ' ' is mapped to the 'DbFunction' named ' '…
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)