Why Polymorphic Relations Are "Bad" and Why I Still Use Them

Why Polymorphic Relations Are “Bad” and Why I Still Use Them
If you’ve spent enough time designing relational databases, you’ve probably heard the warning:
Polymorphic relations are an anti-pattern. They break best practices and relational integrity.
And that’s partially true. Polymorphic relations don’t enforce strict foreign keys, can be hard to query, and often trigger raised eyebrows during code reviews.
But here’s the other side of the story: in the real world, especially when building flexible, evolving systems, polymorphic relations can be a powerful, pragmatic choice.
What Are Polymorphic Relations?
A polymorphic relation allows a single table to be associated with multiple different models. Instead of defining a unique relation table for every entity combination, you store both the related object’s ID and its type in the same table.
Let’s take a practical, real-world example.
Imagine you’re building a system where different models can have media attached, users have profile pictures, projects have images, products have galleries, and reports have PDFs.
You could create individual pivot tables for each relationship:
user_mediaproject_mediaproduct_mediareport_media
That’s four different tables, all doing exactly the same thing.
Or you could define a single media table like this:
medias
---------
id
url
mediable_id
mediable_typeNow, any model can be “media-capable” just by implementing a simple contract or trait such as HasMedia. No redundant tables. No duplicated logic. Just a clean, consistent way to attach files to anything.
Why People Say Polymorphic Relations Are “Bad”
They break referential integrity Because
mediable_idcan refer to multiple tables, you can’t enforce foreign key constraints at the database level. If a parent record (like a Product or a Report) is deleted, its media could become orphaned unless you handle it manually.Complex queries You can’t rely on standard SQL joins. Loading related data often requires conditional logic or ORM-level resolution.
Performance and indexing challenges The database can’t optimize lookups as efficiently since
mediable_idstores references to multiple entity types.Migration friction Adding new “media-capable” models means updating application logic rather than database structure.
Hidden complexity The schema looks deceptively simple, but the relationship logic can be abstract and harder to trace for new developers.
These are valid criticisms, but they don’t tell the full story.
Breaking the Rules (When It Makes Sense)
Polymorphic relations are often labeled as bad because they break normalization principles. But ask yourself this:
Do you never store JSON in a TEXT or BLOB column? Does WordPress not serialize data directly in MySQL?
Of course it does. And it works perfectly fine.
In the real world, outside of academic database theory, there are many scenarios where it’s reasonable, even smart, to break the rules. Depending on your specific use case, the benefits can far outweigh the downsides.
Why I Chose a Polymorphic Media Relation
In my case, I wanted a clean way to handle file attachments across multiple entities in an application. Instead of scattering logic across numerous pivot tables, I wanted something simple and expressive:
user.medias
project.medias
document.mediasThat’s it.
With a polymorphic media relation, I gained:
- A single, consistent interface for all models.
- A simplified schema one table instead of many.
- Less boilerplate in controllers and repositories.
- Easier future extension I can add new media-enabled models without touching the database.
In short, it let me focus on behavior instead of plumbing.
The Benefits Outweigh the Downsides
Critics often forget that a database schema is a tool, not a doctrine. When a design pattern improves maintainability, development speed, and domain clarity, that’s a win even if it bends the “rules.”
Here’s why I think polymorphic relations still deserve their place:
They drastically reduce redundancy One table for all media rather than dozens of repetitive pivot tables.
They mirror code-level polymorphism Your database reflects your domain logic, different entities share common behaviors through the same structure.
They make APIs more flexible If tomorrow you introduce a new entity, like an Invoice, that needs file attachments, it’s plug-and-play.
They simplify business logic Common services, like a file uploader or cleaner, can operate generically on any model.
Their “downsides” are easy to mitigate Referential integrity can be enforced at the application level, and performance issues are negligible with proper indexing and caching.
The Real Perspective
Polymorphic relations are not inherently bad — they’re just misunderstood. Yes, they bend normalization principles. Yes, they can complicate queries. But in return, they offer simplicity, flexibility, and expressiveness that many applications genuinely benefit from.
A clean, pragmatic architecture often beats a theoretically perfect one that’s painful to evolve.
Final Thoughts
Polymorphic relations shouldn’t be your default for everything, but they should absolutely be in your architectural toolbox. Used deliberately, they make your data model simpler, more consistent, and easier to extend and that’s what good engineering is about.
In the end, the “bad” points people bring up are mostly theoretical. In practice, their advantages often outweigh their drawbacks especially in domains where flexibility and maintainability matter more than textbook purity.
