Entity Framework
Code First
Cascade Delete
Link Tables
Database Relationships

How to disable cascade delete for link tables in EF code-first?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

In Entity Framework Code First, cascade delete is often introduced by convention when relationships are required. If you want explicit control over what happens to rows in a link table, the cleanest solution is usually to model the join table as its own entity and disable cascade behavior on the foreign-key relationships.

A pure many-to-many mapping in older EF versions hides the join table from your domain model. That is convenient until you need to control details such as:

  • cascade delete behavior,
  • additional columns on the join table,
  • or explicit cleanup rules.

Once you need that control, an explicit join entity is usually the better design.

Model the Join Table Explicitly

Suppose you have Student, Course, and a link table Enrollment. Instead of relying on an implicit many-to-many relationship, create a join entity.

csharp
1public class Student
2{
3    public int Id { get; set; }
4    public string Name { get; set; }
5    public virtual ICollection<Enrollment> Enrollments { get; set; } = new List<Enrollment>();
6}
7
8public class Course
9{
10    public int Id { get; set; }
11    public string Title { get; set; }
12    public virtual ICollection<Enrollment> Enrollments { get; set; } = new List<Enrollment>();
13}
14
15public class Enrollment
16{
17    public int StudentId { get; set; }
18    public int CourseId { get; set; }
19
20    public virtual Student Student { get; set; }
21    public virtual Course Course { get; set; }
22}

This makes the link table a first-class part of the model instead of hidden EF infrastructure.

Disable Cascade Delete in Fluent Configuration

Once the join entity is explicit, you can configure each required relationship and turn cascade delete off.

csharp
1using System.Data.Entity.ModelConfiguration;
2
3public class EnrollmentConfiguration : EntityTypeConfiguration<Enrollment>
4{
5    public EnrollmentConfiguration()
6    {
7        HasKey(e => new { e.StudentId, e.CourseId });
8
9        HasRequired(e => e.Student)
10            .WithMany(s => s.Enrollments)
11            .HasForeignKey(e => e.StudentId)
12            .WillCascadeOnDelete(false);
13
14        HasRequired(e => e.Course)
15            .WithMany(c => c.Enrollments)
16            .HasForeignKey(e => e.CourseId)
17            .WillCascadeOnDelete(false);
18    }
19}

That tells EF not to create cascade delete on either foreign key, even though both relationships are required.

Register the Configuration

Make sure the configuration is applied in your context:

csharp
1using System.Data.Entity;
2
3public class SchoolContext : DbContext
4{
5    public DbSet<Student> Students { get; set; }
6    public DbSet<Course> Courses { get; set; }
7    public DbSet<Enrollment> Enrollments { get; set; }
8
9    protected override void OnModelCreating(DbModelBuilder modelBuilder)
10    {
11        modelBuilder.Configurations.Add(new EnrollmentConfiguration());
12        base.OnModelCreating(modelBuilder);
13    }
14}

After updating the model, create and apply a migration so the database schema matches the new relationship rules.

What This Changes Operationally

With cascade delete disabled, deleting a Student or Course does not automatically remove related Enrollment rows. That means your application must decide what to do:

  • delete enrollments first,
  • reject the delete,
  • or reassign the relationship if that makes sense.

This is often the whole point. You are choosing explicit cleanup logic over automatic deletion.

Why Not Keep the Implicit Many-to-Many Mapping?

If EF manages the link table implicitly, your control is limited. For simple cases, that is fine. But if the question is specifically about disabling cascade delete for link tables, the explicit join entity is usually the most maintainable answer because it gives you full relationship configuration.

It also scales better when the link table later needs extra columns such as CreatedAt, Role, or Status.

Common Pitfalls

  • Expecting fine-grained cascade control while still using a completely implicit many-to-many mapping.
  • Disabling cascade delete without deciding how orphaned link rows will be handled.
  • Updating the Fluent API but forgetting to create and apply a migration.
  • Assuming EF conventions will always produce the delete behavior you actually want.
  • Treating the join table as hidden infrastructure even when it clearly carries business meaning.

Summary

  • Cascade delete on link tables is easiest to control when the join table is modeled explicitly.
  • Create a join entity instead of relying on a hidden many-to-many mapping.
  • Use Fluent API and WillCascadeOnDelete(false) on the foreign-key relationships.
  • Apply the configuration in OnModelCreating and update the database with a migration.
  • Once cascade delete is disabled, cleanup becomes an explicit application decision instead of an automatic database action.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.