Multiple Inheritance in C#: Interfaces, the Diamond Problem and Composition (.NET 10)

Most people’s first try at multiple inheritance in C# looks like class Thermostat : Device, WifiModule. It won’t compile. The .NET 10 compiler stops with CS1721, because a C# class can have only one base class.

Quick answer: keep one base class and implement as many interfaces as you need: class Thermostat : Device, INetworked, ISchedulable. When you need shared code, not just a contract, use default interface methods or composition. I ran each snippet on .NET 10.

Why Doesn’t C# Support Multiple Inheritance of Classes?

Here’s the exact code I see in questions all the time. A smart thermostat for an Austin, Texas installer is a Device and it has Wi-Fi, so it inherits from both:

var hallway = new Thermostat();

class Device { public string Serial { get; init; } = "TX-1042"; }
class WifiModule { public void Connect() { } }

class Thermostat : Device, WifiModule { }   // two base classes

Output:

C:\DotNetDemo\MultiInheritDemo\TwoBases.cs(6,28): error CS1721: Class 'Thermostat' cannot have multiple base classes: 'Device' and 'WifiModule'

The build failed. Fix the build errors and run again.
Multiple inheritance in C# error CS1721: class Thermostat cannot have multiple base classes Device and WifiModule, VS Code terminal
dotnet run stops at CS1721 before the program starts

The reason is the diamond problem. If Device and WifiModule both inherited a Reset() from a shared parent and each changed it, which version would the thermostat run? And which copy of the parent’s fields would it hold?

C++ answers that with virtual base classes and scope rules. C# avoids it: one base class for state and code, any number of interfaces for contracts. The single chain is covered in my guide to inheritance in C#.

How to Achieve Multiple Inheritance in C# with Interfaces

An interface in C# is a contract with no instance fields. A class lists one base class first, then any interfaces after the comma, and must implement every member they declare. Same thermostat, fixed:

var hallway = new Thermostat { Serial = "TX-1042" };
hallway.Connect("HomeNet-Austin");
hallway.SetSchedule(68, 76);
Console.WriteLine($"Device: {hallway is Device}");
Console.WriteLine($"INetworked: {hallway is INetworked}");
Console.WriteLine($"ISchedulable: {hallway is ISchedulable}");

interface INetworked { void Connect(string network); }
interface ISchedulable { void SetSchedule(int heat, int cool); }
class Device { public string Serial { get; init; } = ""; }

class Thermostat : Device, INetworked, ISchedulable
{
    public void Connect(string network) =>
        Console.WriteLine($"{Serial} joined {network}");
    public void SetSchedule(int heat, int cool) =>
        Console.WriteLine($"Heat {heat} F, cool {cool} F");
}

Output:

TX-1042 joined HomeNet-Austin
Heat 68 F, cool 76 F
Device: True
INetworked: True
ISchedulable: True
C# multiple inheritance with interfaces: Thermostat inherits Device and implements INetworked and ISchedulable, VS Code output
One base class plus two interfaces: the thermostat is all three types at once

Thermostat TX-1042 joined HomeNet-Austin, took a 68/76 schedule, and all three type checks print True for Device, INetworked and ISchedulable. That’s the polymorphism you wanted from multiple inheritance.

Note: the base class must come first in the list. Interfaces can also inherit from several other interfaces, e.g. interface ISmartThermostat : INetworked, ISchedulable { }.

Default Interface Methods and Multiple Inheritance (C# 8+)

Plain interfaces only describe behavior. Since C# 8, an interface member can carry a body, so you can share code across classes without a common base class. Same thermostat, two interfaces that each ship a default Describe():

var hallway = new Thermostat();
INetworked net = hallway;
ISchedulable plan = hallway;
Console.WriteLine(net.Describe());     // default body from INetworked
Console.WriteLine(plan.Describe());    // default body from ISchedulable
// hallway.Describe();                 // CS1061: Thermostat doesn't inherit default bodies

interface INetworked { string Describe() => "Networked over Wi-Fi"; }
interface ISchedulable { string Describe() => "Runs a weekday schedule"; }

class Thermostat : INetworked, ISchedulable { }

Output:

Networked over Wi-Fi
Runs a weekday schedule

Two things surprise people here. First, Thermostat compiles even though both interfaces have a Describe() body, because the two members are unrelated. Second, the class doesn’t inherit those bodies.

You call a default member through an interface reference. Uncomment hallway.Describe(); and the build fails with CS1061, which I checked on .NET 10. Interfaces still can’t hold instance fields, so defaults can’t keep per-object state.

The Diamond Problem with Default Interface Methods (CS8705)

Default methods bring a small diamond back. Give ISmartDevice a default Status(), let IWifi and IZigbee both override it, and implement both:

var hallway = new Thermostat();

interface ISmartDevice
{ string Status() => "Device online"; }
interface IWifi : ISmartDevice
{ string ISmartDevice.Status() => "Wi-Fi connected"; }
interface IZigbee : ISmartDevice
{ string ISmartDevice.Status() => "Zigbee paired"; }

class Thermostat : IWifi, IZigbee { }   // which Status() wins?

Output:

C:\DotNetDemo\MultiInheritDemo\Diamond.cs(10,20): error CS8705: Interface member 'ISmartDevice.Status()' does not have a most specific implementation. Neither 'IWifi.ISmartDevice.Status()', nor 'IZigbee.ISmartDevice.Status()' are most specific.

The build failed. Fix the build errors and run again.
C# default interface methods diamond problem: error CS8705 ISmartDevice.Status() does not have a most specific implementation, VS Code terminal
Two interfaces override the same default member, so neither is most specific

The compiler refuses to guess which override you meant. The fix is to give the class its own implementation, which is always the most specific one:

ISmartDevice hallway = new Thermostat();
Console.WriteLine(hallway.Status());

interface ISmartDevice
{ string Status() => "Device online"; }
interface IWifi : ISmartDevice
{ string ISmartDevice.Status() => "Wi-Fi connected"; }
interface IZigbee : ISmartDevice
{ string ISmartDevice.Status() => "Zigbee paired"; }

class Thermostat : IWifi, IZigbee
{
    // the class's own member is the most specific one
    public string Status() => "Wi-Fi connected, Zigbee paired";
}

Output:

Wi-Fi connected, Zigbee paired

Calling Status() through an ISmartDevice reference now prints the class’s text. It’s the same rule as method overriding in C#: the most derived implementation runs.

Explicit Interface Implementation When Two Interfaces Clash

Sometimes two interfaces declare the same signature with different meanings. The US wall display wants Fahrenheit, and a cloud API wants Celsius. Explicit interface implementation lets one class answer both:

var hallway = new Thermostat(72);
var f = ((IFahrenheit)hallway).Read();
var c = ((ICelsius)hallway).Read();
Console.WriteLine($"Wall display: {f} F");
Console.WriteLine($"Cloud API:    {c} C");
// hallway.Read();   // CS1061: needs an interface

interface IFahrenheit { double Read(); }
interface ICelsius { double Read(); }

class Thermostat(double fahrenheit)
    : IFahrenheit, ICelsius
{
    double IFahrenheit.Read() => fahrenheit;
    double ICelsius.Read() =>
        Math.Round((fahrenheit - 32) / 1.8, 1);
}

Output:

Wall display: 72 F
Cloud API:    22.2 C
C# explicit interface implementation: IFahrenheit.Read returns 72 and ICelsius.Read returns 22.2 on the same Thermostat, VS Code output
Same method name, two answers: the cast picks which interface you’re talking to

The same object returned 72 F and 22.2 C. Explicit members have no access modifier and don’t show up on the class itself, so hallway.Read() won’t compile. That keeps the public surface clean, which ties into encapsulation in C#.

Composition Instead of Multiple Inheritance in C#

Interfaces give you the types; composition gives you reusable code with state. Instead of inheriting from WifiModule, the thermostat has a radio and a scheduler, and delegates to them:

var radio = new WifiRadio("HomeNet-Austin");
var hallway = new Thermostat("Hallway", radio,
    new Scheduler(dayF: 72, nightF: 66));
hallway.Connect();
hallway.Tick(7);
hallway.Tick(23);

class WifiRadio(string network)
{ public string Join() => $"joined {network}"; }
class Scheduler(int dayF, int nightF)
{ public int TargetFor(int hour) =>
      hour is >= 6 and < 22 ? dayF : nightF; }
class Thermostat(string room, WifiRadio radio,
    Scheduler plan)
{
    public void Connect() =>   // delegate to the radio
        Console.WriteLine($"{room} {radio.Join()}");
    public void Tick(int hour) => Console.WriteLine(
        $"{hour}:00 -> {plan.TargetFor(hour)} F");
}

Output:

Hallway joined HomeNet-Austin
7:00 -> 72 F
23:00 -> 66 F
C# composition instead of multiple inheritance: Thermostat delegates to WifiRadio and Scheduler objects passed into its constructor, VS Code output
The thermostat reuses two classes’ code without inheriting from either

At 7:00 the target is 72 F, and at 23:00 it drops to 66 F. The radio and scheduler are plain objects passed to the primary constructor, so you can swap a Zigbee radio in without touching Thermostat.

Pro Tip: combine both ideas. Let the class implement INetworked and forward the call to a private radio field. That’s how the decorator and strategy patterns get multiple-inheritance-like reuse.

Multilevel vs Multiple Inheritance in C#

You’ll see these mixed up in interviews. Multilevel inheritance is a chain, and C# allows it as deep as you like, because every class still has exactly one parent:

var hallway = new Thermostat();
for (Type? t = hallway.GetType(); t is not null; t = t.BaseType)
    Console.WriteLine(t.Name);

class Device { }
class NetworkedDevice : Device { }       // level 2
class Thermostat : NetworkedDevice { }   // level 3: still one base class each

Output:

Thermostat
NetworkedDevice
Device
Object
MultilevelMultiple
ShapeA chain: Device > NetworkedDevice > ThermostatOne class, two or more parents
Classes in C#AllowedNot allowed (CS1721)
Interfaces in C#AllowedAllowed
Diamond riskNoneOnly with default interface methods (CS8705)

Every chain ends at Object, as the output shows. Mark a middle class abstract when it should never be created on its own; my abstract class in C# guide covers that.

Can a Struct Implement Multiple Interfaces in C#?

Yes. A struct can’t inherit from a class or another struct (try it and you get CS0527, “Type ‘Device’ in interface list is not an interface”), but it can implement any number of interfaces:

var readings = new List<Reading> { new(72.5), new(68.0), new(70.1) };
readings.Sort();                                   // uses IComparable<Reading>
Console.WriteLine(string.Join(", ", readings));
Console.WriteLine($"Equal: {readings[0] == new Reading(68.0)}");   // IEquatable<Reading> from the record

readonly record struct Reading(double F) : IComparable<Reading>
{
    public int CompareTo(Reading other) => F.CompareTo(other.F);
    public override string ToString() => $"{F:0.0} F";
}

Output:

68.0 F, 70.1 F, 72.5 F
Equal: True

The readings sorted to 68.0, 70.1 and 72.5 F through IComparable<Reading>, and the record struct added IEquatable<Reading> for free. Assigning a struct to an interface variable boxes a copy, as I show in boxing and unboxing in C#.

Common Multiple Inheritance Errors and How to Fix Them

ErrorWhat triggers itFix
CS1721Two classes in a class’s base listKeep one base class; turn the other into an interface or a field
CS0527A class in a struct’s or interface’s base listImplement interfaces only
CS0535A listed interface member isn’t implementedImplement it, or mark the class abstract
CS8705Two interfaces override the same default memberImplement the member in the class
CS1061Calling a default or explicit member on the class variableCast to the interface first

Interface, Abstract Class or Composition: Which Replaces Multiple Inheritance?

My rule on client projects: use a base class for the one “is-a” relationship that shares state, interfaces for every capability on top, and composition when you need to reuse code from more than one place.

Reach for default interface methods mainly to add a member to a published interface without breaking implementers. For the bigger design picture, abstraction in C# and the four OOP pillars in C# are good next reads.

If you’re working through the rest of the object-oriented side of C#, these fit well:

Frequently Asked Questions

Does C# support multiple inheritance?

Not for classes. A C# class can inherit from only one base class, but it can implement any number of interfaces, and an interface can inherit from several interfaces.

How do you achieve multiple inheritance in C#?

Inherit one base class and implement several interfaces, for example class Thermostat : Device, INetworked, ISchedulable. Use default interface methods or composition when you also need shared code.

What is the diamond problem in C#?

It’s the ambiguity when a type gets the same member from two parents. Classes avoid it by allowing one base class. With default interface methods it shows up as error CS8705, which you fix by implementing the member in the class; see interface implementation errors on Microsoft Learn.

Can an interface inherit from multiple interfaces in C#?

Yes. interface ISmartThermostat : INetworked, ISchedulable { } is valid, and a class that implements it must implement the members of all three interfaces.

Why can’t I call a default interface method on my class?

Default interface members aren’t inherited by the class. Call them through an interface reference, such as ((INetworked)hallway).Describe(), or implement the member in the class.

Is multilevel inheritance the same as multiple inheritance?

No. Multilevel is a chain where each class has one parent (Device, NetworkedDevice, Thermostat), and C# allows it. Multiple means one class with two parents, which C# allows only through interfaces.