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

  1. Return a non-owned entity type from the DbFunction (define a standalone entity for the TVF row shape).
  2. 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.
  3. 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

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


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/e68ec90584022bd9. Report an issue: GitHub.