Composition Over Inheritance: Why Epic Is Replacing the Actor Tree
"Favor composition over inheritance" has been circulating in software for thirty years, and most people only kept the slogan. This page takes it apart: how inheritance actually breaks down at scale, which class of problem composition solves, and what it costs you — the part tutorials usually skip, and the part you will eventually run into.
1. Three Ways Inheritance Breaks
Credit where it's due: inheritance is not wrong. When a project has 30 classes, inheritance is the cheapest reuse mechanism there is — write the base once, subclasses get it free. The trouble comes from scale and from the shape of your requirements.
Failure one: the diamond problem. You have Movable and Interactable as two capability lines, each a base class. Now you need something that both moves and can be used — which one does it extend? Blueprints and most engine type systems allow single inheritance only, so you pick one parent and either copy the other's code across or route around it with an Actor Component. The name comes from the diamond shape in the class diagram: two lines branch from a shared ancestor and then want to merge again, and single inheritance won't let them.
The important part: this is not "a missing engine feature". Even where multiple inheritance is allowed (C++ allows it), the diamond just changes form — both paths inherit the same ancestor, so does that ancestor's state exist once or twice? Which one do you call? C++ invented virtual inheritance to answer that, and the complexity of virtual inheritance is itself a deterrent. The root isn't syntax. It's the premise that a thing may belong to only one line of classification.
Failure two: the God class. Diamonds are annoying, so most teams take the other road: pour every capability anyone might need into one sufficiently fat base class, gated by booleans. In month one it's BP_ActorBase with six functions. By month eight it has 2,000 nodes, 31 variables, and eleven comments reading "who uses this toggle?"
The real damage isn't file size, it's blast radius. You change one line in the base to fix a chest bug, and in theory every descendant is affected — 47 doors, 12 chests, 8 platforms, 3 NPCs. You can't test all of it, so you choose not to change it; so the next person adds another toggle beside yours. That's the mechanism that manufactures legacy sludge: it isn't that nobody wants to clean it up, it's that inheritance multiplies the cost of cleaning up.
Failure three: more than one axis of classification. This one is the root cause of the other two. Inheritance is a tree, and a tree expresses exactly one axis. How many does your game have? Can it move, can it be used, can it take damage, does it need network replication, can the player pick it up… five binary axes is 32 combinations. Expressing 32 combinations with a tree means either 32 classes (explosion) or stuffing the axes into toggles (God class).
This also explains a counter-intuitive observation: inheritance looks elegant on small projects precisely because small projects have few axes. Add axes and the tree buckles — no reflection on the team's skill.
2. What Composition Actually Solves
Composition chops down the tree and replaces it with a checklist: an object equals "one empty container plus the capabilities it carries". Five axes of classification? That's five ability cards; take whichever you want. 32 combinations need 32 classes under inheritance and 5 cards under composition.
This family of designs has a more academic name in games: ECS (Entity–Component–System). Textbook ECS keeps three things strictly apart: an entity is just an ID, a component holds only data, and a system is the logic that iterates over that data. Industry implementations are rarely that pure — Unity's GameObject/MonoBehaviour, Unreal's Actor Components, and UEFN's Scene Graph are all composition-based but keep data and behavior together in the component (Epic's own definition of a component is "provide data and behavior to an entity"). So the precise statement is: Scene Graph is a composition-based architecture that borrows the ECS idea, and you shouldn't try to read it through textbook-ECS dogma.
With the axis swapped, here's what happens to the three failures:
| Problem in the inheritance era | What happens under composition |
|---|---|
| Diamond: what does "movable and interactable" extend? | The question disappears — attach both cards, neither is anyone's parent |
| God class: the base keeps getting fatter | There is no base to fatten. Capability lives in separate components, one job per card |
| Blast radius: one line ripples everywhere | Editing a card affects only the objects carrying it. The scope is on the checklist, visible to the eye |
| Combinatorial explosion: 32 combos need 32 classes | 5 cards cover 32 combos, and a new combo needs no new type at all |
There's one more motive that gets less airtime but matters a lot to Epic: portability. An assembled object is "a checklist", which is naturally easy to serialize, carry between projects, and read or write with tooling. When your goal is a metaverse where assets move between experiences, "this object is a node on a 47-level inheritance chain" is very hard to carry across, while "this object is one entity plus five cards" is comparatively easy.
3. The Cost: Three Honest Line Items
If composition were pure upside, inheritance would be extinct. It isn't, because the ledger has two sides.
Cost one: more indirection — "what does this thing do" stops being obvious. Under inheritance you open BP_GlowingDoor, walk up the parent chain, and the behavior chain is long but linear, and the IDE will jump you along it. Under composition an entity's behavior is the sum of every component on it, plus whatever its parent and child entities contribute — so you read the Details panel card by card, and cards may carry implicit ordering dependencies between them. The information didn't grow. It scattered.
Cost two: harder debugging. A direct consequence of cost one. "The lid didn't open" used to mean: open that class, drop a breakpoint, follow the execution wire. Now you first have to answer: did the animation card not fire, did the interaction card not raise its event, or did the event fire and go to the wrong entity? Epic's own best-practices page has a telling recommendation — avoid repeated wide hierarchy scans during gameplay; instead find the child components you need once on begin simulation, store the references or subscribe to their events, and react to events rather than searching the graph again each time. That guidance exists in the docs precisely because "who finds whom" is a real problem in composition-based architectures.
Cost three: communication overhead and mental load. Under inheritance, calling the parent's function is one line. Under composition, if card A wants card B to act, A first has to find B (on the same entity? on a child entity?) and then call it or send an event. That's why Scene Graph ships explicit mechanisms for sending scene events up and down the hierarchy, and why the best-practices page pointedly advises that events should be targeted narrowly — don't broadcast across large parts of the graph when a local approach works. Flexibility has a price, and the price is that you maintain the "who knows whom" web yourself.
One last item that's a warning rather than a cost: composition is not a get-out-of-jail card. Split too finely and you end up with 40 interdependent cards and a relationship web nobody can read — the same sludge in a different shape. How fine is just right is covered in the technique extra, A thought exercise: breaking an Actor Blueprint into components.
4. So What Should I Do Today
Pragmatically: Actors and Blueprints are fully supported in UE6 Early Access (targeted for the end of 2027) and in the early releases; deprecation waits until Scene Graph is sufficiently mature, with no date given; Epic has committed to conversion tools, but they are not released yet. So this page is not telling you to go refactor your project today.
There is exactly one thing worth doing right now that pays off even if Scene Graph never arrives: use more Actor Components and add fewer inheritance layers in your existing Blueprint project. Next time the designer asks for a glowing door, don't create BP_GlowingDoor — build a glow Component and attach it wherever it's needed. That is simply the better pattern inside the Actor system anyway, and as a bonus it bends your project into the shape of "a pile of ability cards" ahead of time. Whether you migrate by hand later or wait for Epic's tools, a checklist that's already split apart is easier to carry than a tangled inheritance tree.
5. Quick Quiz
Which of these is a cost of composition relative to inheritance, rather than a benefit?
Sources
Framework facts and best practices are taken from Epic's official documentation: Scene Graph in Unreal Editor for Fortnite (official docs) ↗ · Getting Started in Scene Graph in Fortnite (official docs) ↗ · Scene Graph Best Practices in Fortnite (official docs) ↗ · The Road to Unreal Engine 6 (Epic announcement) ↗
The discussion of the diamond problem, God classes and ECS is general software-engineering knowledge, not an Epic statement; whether Scene Graph internally follows textbook ECS is a question for the official documentation.