dotnet/efcore · error · InvalidOperationException
The DbFunction '{function}' has an invalid return type '{typ
Error message
The DbFunction '{function}' has an invalid return type '{type}'. Owned entity types cannot be used as the return type of a DbFunction. What it means
ValidateDbFunction (RelationalModelValidator.cs:378-385) throws for a non-scalar (IQueryable-returning) DbFunction whose element type is an owned entity type. Owned entity types are tied to an owner and cannot stand alone as the row type of a TVF/result set, so using one as a DbFunction's IQueryable<T> return is rejected.
Source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:382
{
if (dbFunction.TypeMapping == null)
{
throw new InvalidOperationException(
RelationalStrings.DbFunctionInvalidReturnType(
dbFunction.ModelName,
dbFunction.ReturnType.ShortDisplayName()));
}
}
else
{
var elementType = dbFunction.ReturnType.GetGenericArguments()[0];
var entityType = model.FindEntityType(elementType);
if (entityType?.IsOwned() == true
|| ((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()));
}
}View on GitHub (pinned to dbf9771522)
Solutions
- Return a non-owned entity type from the DbFunction (define a standalone entity for the TVF row shape).
- If you need the owned shape, project to a separate non-owned DTO/entity type registered in the model and map the TVF to that.
- Remove the Owns* configuration if the type should be independent and usable as a TVF row.
Example fix
// before public IQueryable<Address> AddressesInCity(string city) => null!; modelBuilder.Entity<User>().OwnsOne(u => u.Address); modelBuilder.HasDbFunction(() => AddressesInCity(default)); // Address is owned -> throws // after - use a standalone (non-owned) entity for the TVF row public IQueryable<AddressView> AddressesInCity(string city) => null!; modelBuilder.Entity<AddressView>().HasNoKey(); modelBuilder.HasDbFunction(() => AddressesInCity(default));
Defensive patterns
Strategy: validation
Validate before calling
foreach (var fn in context.Model.GetDbFunctions())
{
if (!fn.IsScalar)
{
var elementType = fn.ReturnType.GetGenericArguments()[0];
var et = context.Model.FindEntityType(elementType);
if (et?.IsOwned() == true
|| ((IConventionModel)context.Model).IsOwned(elementType))
{
// will throw - return a non-owned entity type from this DbFunction.
}
}
} Prevention
- Never use an owned entity type as a DbFunction's IQueryable<T> element.
- Define a standalone (often keyless) entity for TVF row shapes.
- Review ownership when promoting a query to a DbFunction.
When it happens
Trigger: Declaring HasDbFunction returning IQueryable<OwnedEntity> where OwnedEntity is configured with OwnsOne/OwnsMany (owned). Thrown at model validation.
Common situations: Trying to expose a TVF whose row shape is an owned type; refactoring a query to a DbFunction without realizing the row type is owned; aggregating owned entities into a function result.
Related errors
- The DbFunction '{function}' returns '{type}', but '{elementT
- The element type of the result of '{dbFunction}' is mapped t
- The DbFunction '{function}' has an invalid return type '{typ
- The parameter '{parameter}' for the DbFunction '{function}'
- The entity type '{entityType}' is mapped to the DbFunction n
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/e68ec90584022bd9.
Report an issue: GitHub.