Skip to content

EF Core Shadow Property — Complete Guide

DodaTech Updated 2026-06-24 2 min read

In this tutorial, you'll learn about EF Core Shadow Property. We cover key concepts, practical examples, and best practices.

You need a LastModified column on every table for auditing, but you do not want to add a LastModified property to every entity class. Shadow properties let you map database columns that exist only in the EF Core model, not in your entity class.

Wrong

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    // Every entity needs this:
    public DateTime LastModified { get; set; }
}

public class Order
{
    public int Id { get; set; }
    // Also needs LastModified...
    public DateTime LastModified { get; set; }
}

Output: Works. But LastModified is duplicated in every entity. Adding it to 50 entities means 50 property declarations.

// Entity — no LastModified property
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}

// Configuration
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>().Property<DateTime>("LastModified");
}

// Set the value via the context
public override int SaveChanges()
{
    foreach (var entry in ChangeTracker.Entries())
    {
        if (entry.State is EntityState.Added or EntityState.Modified)
        {
            entry.Property("LastModified").CurrentValue = DateTime.UtcNow;
        }
    }
    return base.SaveChanges();
}

Query shadow properties:

var oldProducts = await db.Products
    .Where(p => EF.Property<DateTime>(p, "LastModified") < cutoff)
    .ToListAsync();

Prevention

  • Use shadow properties for cross-cutting concerns (audit timestamps, soft-delete flags, tenant IDs).
  • Use EF.Property<T>(entity, name) to query or set shadow property values.
  • Use shadow properties to keep entity POCOs clean.
  • Use ChangeTracker in SaveChanges to auto-populate shadow properties.
  • Use shadow properties for foreign keys that should not be exposed in the entity.
  • Use [NotMapped] for the opposite — CLR properties not persisted to the database.

Common Mistakes with core shadow property

  1. Forgetting that lazy evaluation defers computation until the value is forced, causing space leaks with unevaluated thunks
  2. Using return to exit a function early instead of wrapping a pure value in the monad
  3. Mixing let bindings with <- bindings in do notation, producing type errors

These mistakes appear frequently in real-world EF code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.

Practice Exercise

Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.

This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.

FAQ

Can I have a shadow property as a foreign key?

Yes. This is the most common use case. When you have a navigation property but no corresponding FK property, EF Core creates a shadow FK property automatically. You can also explicitly configure it: entity.HasOne(e => e.Category).WithMany().HasForeignKey("CategoryId").

How do I set a shadow property in a query?

Use the EF.Property<T> static method: .Where(p => EF.Property<bool>(p, "IsDeleted")). This translates to SQL correctly. For ordering: .OrderBy(p => EF.Property<DateTime>(p, "LastModified")).

Can I index a shadow property?

Yes. Use Fluent API: entity.HasIndex("LastModified"). Shadow properties support all configuration options that regular properties support, including indexes, constraints, and default values.

Shadow properties are used in DodaTech's audit infrastructure across all entities. For more EF Core, visit DodaTech.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro