Structs
Inheritance
Programming
Object-Oriented Design
Software Engineering

Why don't structs support inheritance?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

This question is language-specific, which is why it causes confusion. In C++, struct does support inheritance because it is almost the same construct as class. In C#, struct is a value type, and user-defined struct inheritance is intentionally disallowed.

First Clarify the Language

In C++, the difference between struct and class is mostly the default access level. Inheritance works normally:

cpp
1#include <iostream>
2
3struct Point {
4    int x;
5    int y;
6};
7
8struct ColoredPoint : Point {
9    int color;
10};
11
12int main() {
13    ColoredPoint p{1, 2, 7};
14    std::cout << p.x << ", " << p.y << ", " << p.color << '\n';
15}

So if your mental model comes from C++, the premise of the question is false.

In C#, the story is different. A struct implicitly derives from System.ValueType, cannot derive from another struct or class, and cannot be a base type for other structs or classes.

Why C# Structs Avoid Inheritance

C# structs are designed around value semantics. Copying a struct copies the value. That makes them useful for small data carriers like coordinates, ranges, and timestamps.

Inheritance clashes with that model for several reasons.

Fixed Size Matters

The runtime wants the size of a value type to be known by its declared type. If one struct could inherit from another and add fields, assignment and storage would become much harder to reason about because different "versions" of the value could have different sizes.

Copying Would Be More Error-Prone

When a value is copied, developers expect the whole value to move with it. In an inheritance hierarchy, the language would need rules for base-value copying, slicing, and conversions. Those rules are already subtle in object-oriented code; adding them to value types makes the model harder, not simpler.

Layout and Performance Would Suffer

Value types are meant to stay lightweight. They are commonly embedded inside arrays, other objects, and generic containers. Keeping them simple helps the runtime optimize storage and copying. Allowing arbitrary inheritance would complicate layout and undermine those benefits.

What C# Lets You Do Instead

C# structs can implement interfaces, which gives you polymorphism without building a value-type inheritance tree.

csharp
1public interface ILength
2{
3    double Length();
4}
5
6public readonly struct Vector2 : ILength
7{
8    public Vector2(double x, double y)
9    {
10        X = x;
11        Y = y;
12    }
13
14    public double X { get; }
15    public double Y { get; }
16
17    public double Length() => Math.Sqrt(X * X + Y * Y);
18}
19
20var v = new Vector2(3, 4);
21Console.WriteLine(v.Length());

This keeps the data flat and predictable while still allowing shared behavior through an interface contract.

Use Composition Instead of Inheritance

If you want to "extend" a struct, wrap it inside another type instead of inheriting from it.

csharp
1public readonly struct Point
2{
3    public Point(int x, int y)
4    {
5        X = x;
6        Y = y;
7    }
8
9    public int X { get; }
10    public int Y { get; }
11}
12
13public readonly struct ColoredPoint
14{
15    public ColoredPoint(Point position, ConsoleColor color)
16    {
17        Position = position;
18        Color = color;
19    }
20
21    public Point Position { get; }
22    public ConsoleColor Color { get; }
23}
24
25var p = new ColoredPoint(new Point(10, 20), ConsoleColor.Green);
26Console.WriteLine($"{p.Position.X}, {p.Position.Y}, {p.Color}");

Composition is usually clearer anyway. It says directly that one value contains another value, instead of implying an "is-a" relationship that may not really exist.

Reference Types Solve a Different Problem

If you truly need inheritance, virtual dispatch, and substitution through a base type, you probably want a class. That is not a limitation of structs so much as a sign that you are asking for reference-type behavior.

This rule helps API design. A good struct is typically:

  • small
  • immutable or close to it
  • logically a single value
  • free of deep inheritance concerns

Once the type becomes large, stateful, or polymorphic, a class is usually the cleaner choice.

Common Pitfalls

  • Assuming all languages treat struct the same way. C++ and C# do not.
  • Using mutable structs for complex models. Copies become hard to track and bugs get subtle.
  • Reaching for inheritance when composition expresses the relationship better.
  • Boxing structs through interfaces without realizing there may be allocation and copying costs.
  • Treating structs as "always on the stack." Storage details depend on usage, not only on the keyword.

Summary

  • In C++, structs do support inheritance.
  • In C#, structs do not support user-defined inheritance because they are value types.
  • Value semantics, fixed layout, and predictable copying are the main reasons behind the restriction.
  • C# structs can still implement interfaces for shared behavior.
  • When you want to extend a struct, composition is usually the right tool.

Course illustration
Course illustration

All Rights Reserved.