One of the most powerful features of Odoo as a development platform is its inheritance system. Rather than modifying the original Odoo source code (which would break on every upgrade), developers create new modules that extend existing ones through inheritance.
This keeps your customizations maintainable, isolated, and upgrade-safe.
Why Inheritance Matters
Odoo is an ERP platform with hundreds of built-in modules developed over many years. When you need to customize a feature — adding a field to a sales order, changing a method's behavior, or reusing a model's structure — you should never edit the core files directly.
Instead, Odoo provides inheritance mechanisms that let your module hook into existing models, views, and methods cleanly.
+---------------------------+
| Original Module |
| (e.g., sale) |
| SaleOrder model |
| name, partner, lines |
+---------------------------+
|
| _inherit
v
+---------------------------+
| Your Custom Module |
| Extended SaleOrder |
| + x_custom_field |
| + custom logic |
+---------------------------+
The Four Inheritance Types
| Type | Key Attribute | Creates New Table | Purpose |
|---|---|---|---|
| Classical | _name + _inherit | Yes | New model that copies from existing |
| Extension | _inherit only | No | Extend existing model in-place |
| Prototype | _name + _inherits | Yes | New model that delegates to existing |
| Delegation | _inherits | Yes | Composition via delegation |
1. Classical Inheritance
Classical inheritance creates a new model that inherits fields and behavior from an existing model. The new model gets its own database table and is a separate entity.
from odoo import models, fields
class ProductTemplate(models.Model):
_name = 'product.template'
_inherit = 'product.template'
x_custom_field = fields.Char(string="Custom Field")
When to use it
Use Classical Inheritance when you want to create a new model that shares some structure with an existing model but is otherwise independent.
product.template (original)
name, price, description
|
| Classical Inheritance
v
product.template (your extension)
name, price, description (copied)
x_custom_field (added)
2. Extension Inheritance
Extension inheritance is the most commonly used inheritance type in Odoo. It extends an existing model by adding new fields, methods, or modifying existing behavior — without creating a new table.
The extended model continues to exist with the same name (_name is NOT redefined). The original table is modified to include the new fields.
from odoo import models, fields
class SaleOrder(models.Model):
_inherit = 'sale.order'
x_custom_field = fields.Char(string="Custom Field")
def action_confirm(self):
super(SaleOrder, self).action_confirm()
# Custom logic runs after the original confirmation
for order in self:
order.x_custom_field = 'Confirmed'
Key Points
_inheritis set but_nameis not redefined- The model keeps its original name and table
- New fields are added as columns to the existing table
- Methods can be overridden with
super()to call the original implementation
Calling the Parent Method
Always call super() when overriding CRUD methods or action methods, unless you intentionally want to replace the entire behavior:
def write(self, vals):
# Pre-processing
result = super(SaleOrder, self).write(vals)
# Post-processing
return result
When to use it
This is your go-to inheritance type for customizing existing Odoo modules — adding fields to sales orders, modifying partner logic, extending invoice behavior, etc.
sale.order (original Odoo module)
partner_id, order_lines, amount_total
|
| Extension (_inherit only)
|
sale.order (now includes your additions)
partner_id, order_lines, amount_total
x_custom_field ← added by you
3. Prototype Inheritance
Prototype inheritance creates a new model that uses another model's fields via a Many2one link but adds its own fields and behavior on top.
The new model has a _name (its own table) and uses _inherits (not _inherit) to delegate fields from the linked model.
from odoo import models, fields
class NewPartner(models.Model):
_name = 'new.partner'
_inherits = {'res.partner': 'partner_id'}
partner_id = fields.Many2one(
'res.partner',
required=True,
ondelete='cascade'
)
x_custom_field = fields.Char(string="Custom Field")
How It Works
new.partner table
id | partner_id (FK) | x_custom_field
1 | 42 | "VIP"
res.partner table
id | name | email
42 | "Amr" | "amr@example.com"
When you access new_partner.name, Odoo transparently delegates the lookup to the linked res.partner record.
When to use it
Use Prototype Inheritance when you need to create a specialized version of an existing entity with additional attributes, while still reusing all the original entity's fields and behavior.
4. Delegation Inheritance
Delegation inheritance is structurally similar to Prototype Inheritance — it uses _inherits to delegate fields to another model via a Many2one relationship. The difference is conceptual: Delegation is used for composition rather than specialization.
from odoo import models, fields
class PartnerExtension(models.Model):
_name = 'partner.extension'
_inherits = {'res.partner': 'partner_id'}
partner_id = fields.Many2one(
'res.partner',
required=True,
ondelete='cascade'
)
x_custom_field = fields.Char(string="Custom Field")
`_inherit` vs `_inherits`
| Attribute | Type | Creates Table | Delegates |
|---|---|---|---|
_inherit (string) | Extension Inheritance | No | No |
_inherit (string) + _name | Classical Inheritance | Yes | No |
_inherits (dict) | Delegation/Prototype | Yes | Yes |
Overriding Views with Inheritance
Inheritance in Odoo applies not just to models but also to views (the XML UI definitions). You can extend an existing view to add, remove, or modify fields without touching the original XML.
<odoo>
<record id="view_order_form_inherit_custom" model="ir.ui.view">
<field name="name">sale.order.form.inherit.custom</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<!-- Add a new field inside the sheet -->
<sheet position="inside">
<group>
<field name="x_custom_field"/>
</group>
</sheet>
</field>
</record>
</odoo>
View Inheritance Positions
| Position | Description |
|---|---|
inside | Insert content inside the matched element |
before | Insert content before the matched element |
after | Insert content after the matched element |
replace | Replace the matched element entirely |
attributes | Modify the matched element's attributes |
Best Practices for Odoo Inheritance
Always use a custom module — never modify the original Odoo source files.
Use Extension Inheritance by default — it is the most common and cleanest approach for adding fields and methods.
Always call super() when overriding methods unless you intentionally want to skip the original logic.
Prefix custom fields with x_ — this is the Odoo convention for custom fields to avoid naming conflicts with future Odoo updates.
Keep modules focused — each custom module should extend one specific area of functionality, making it easier to maintain and upgrade.
Good Module Design:
custom_sale_features/ ← sale-specific customizations
custom_stock_features/ ← stock-specific customizations
custom_partner_fields/ ← partner-specific customizations
Avoid:
big_customization_module/ ← everything mixed together
Inheritance Decision Guide
What do you need to do?
|
+-- Add fields or methods to an existing model?
| --> Extension Inheritance (_inherit only)
|
+-- Create a brand new model based on an existing one?
| --> Classical Inheritance (_name + _inherit)
|
+-- Create a specialized model that reuses all fields
| from another model?
| --> Prototype / Delegation (_inherits)
|
+-- Share common fields/logic across multiple models?
--> Abstract Model (models.AbstractModel)
Final Thoughts
Odoo's inheritance system is one of its greatest strengths as a development platform. It enables a clean separation between the core product and your customizations, ensuring that your work survives Odoo version upgrades with minimal rework.
Mastering these four inheritance types — Classical, Extension, Prototype, and Delegation — gives you the full toolkit to customize any part of Odoo without compromising the integrity of the original modules.
Customize everything. Break nothing. Upgrade safely.