diff --git a/addons/mrp/models/product.py b/addons/mrp/models/product.py
index 1783fe202f5b4392a8e435546395bc90c4f61cdc..bba2eb9f21561c1a36ef518ada75e30dbc286da7 100644
--- a/addons/mrp/models/product.py
+++ b/addons/mrp/models/product.py
@@ -1,6 +1,7 @@
 # -*- coding: utf-8 -*-
 # Part of Odoo. See LICENSE file for full copyright and licensing details.
 
+import collections
 from datetime import timedelta
 from itertools import groupby
 import operator as py_operator
@@ -222,20 +223,27 @@ class ProductProduct(models.Model):
         # compute kit quantities
         for product in bom_kits:
             bom_sub_lines = bom_sub_lines_per_kit[product]
+            # group lines by component
+            bom_sub_lines_grouped = collections.defaultdict(list)
+            for info in bom_sub_lines:
+                bom_sub_lines_grouped[info[0].product_id].append(info)
             ratios_virtual_available = []
             ratios_qty_available = []
             ratios_incoming_qty = []
             ratios_outgoing_qty = []
             ratios_free_qty = []
-            for bom_line, bom_line_data in bom_sub_lines:
-                component = bom_line.product_id.with_context(mrp_compute_quantities=qties).with_prefetch(prefetch_component_ids)
-                if component.type != 'product' or float_is_zero(bom_line_data['qty'], precision_rounding=bom_line.product_uom_id.rounding):
-                    # As BoMs allow components with 0 qty, a.k.a. optionnal components, we simply skip those
-                    # to avoid a division by zero. The same logic is applied to non-storable products as those
-                    # products have 0 qty available.
-                    continue
-                uom_qty_per_kit = bom_line_data['qty'] / bom_line_data['original_qty']
-                qty_per_kit = bom_line.product_uom_id._compute_quantity(uom_qty_per_kit, bom_line.product_id.uom_id, round=False, raise_if_failure=False)
+
+            for component, bom_sub_lines in bom_sub_lines_grouped.items():
+                component = component.with_context(mrp_compute_quantities=qties).with_prefetch(prefetch_component_ids)
+                qty_per_kit = 0
+                for bom_line, bom_line_data in bom_sub_lines:
+                    if component.type != 'product' or float_is_zero(bom_line_data['qty'], precision_rounding=bom_line.product_uom_id.rounding):
+                        # As BoMs allow components with 0 qty, a.k.a. optionnal components, we simply skip those
+                        # to avoid a division by zero. The same logic is applied to non-storable products as those
+                        # products have 0 qty available.
+                        continue
+                    uom_qty_per_kit = bom_line_data['qty'] / bom_line_data['original_qty']
+                    qty_per_kit += bom_line.product_uom_id._compute_quantity(uom_qty_per_kit, bom_line.product_id.uom_id, round=False, raise_if_failure=False)
                 if not qty_per_kit:
                     continue
                 rounding = component.uom_id.rounding
diff --git a/addons/mrp/tests/common.py b/addons/mrp/tests/common.py
index 96224ab8ecf6ec4c2a3d2b061ee024dd47cd1fc0..e8cc8ccbb29e682e34bd8596d70f3d32e8ec2e77 100644
--- a/addons/mrp/tests/common.py
+++ b/addons/mrp/tests/common.py
@@ -228,3 +228,32 @@ class TestMrpCommon(common2.TestStockCommon):
             'tracking': 'none',
             'categ_id': cls.env.ref('product.product_category_all').id,
         })
+
+    @classmethod
+    def make_prods(cls, n):
+        return [
+            cls.env["product.product"].create(
+                {"name": f"p{k + 1}", "type": "product"}
+            )
+            for k in range(n)
+        ]
+
+    @classmethod
+    def make_bom(cls, p, *cs):
+        return cls.env["mrp.bom"].create(
+            {
+                "product_tmpl_id": p.product_tmpl_id.id,
+                "product_id": p.id,
+                "product_qty": 1,
+                "type": "phantom",
+                "product_uom_id": cls.uom_unit.id,
+                "bom_line_ids": [
+                    (0, 0, {
+                        "product_id": c.id,
+                        "product_qty": 1,
+                        "product_uom_id": cls.uom_unit.id
+                    })
+                    for c in cs
+                ],
+            }
+        )
diff --git a/addons/mrp/tests/test_bom.py b/addons/mrp/tests/test_bom.py
index 28691a2c9b2560a00b760d378b045a1a8efa31c0..7d54adc3f1e755e905b9bd4e42d74989213cb6f9 100644
--- a/addons/mrp/tests/test_bom.py
+++ b/addons/mrp/tests/test_bom.py
@@ -1142,3 +1142,15 @@ class TestBoM(TestMrpCommon):
         self.assertEqual(orderpoint.route_id.id, manufacturing_route_id)
         self.assertEqual(orderpoint.qty_multiple, 2000.0)
         self.assertEqual(orderpoint.qty_to_order, 4000.0)
+
+    def test_bom_kit_with_sub_kit(self):
+        p1, p2, p3, p4 = self.make_prods(4)
+        self.make_bom(p1, p2, p3)
+        self.make_bom(p2, p3, p4)
+
+        loc = self.env.ref("stock.stock_location_stock")
+        self.env["stock.quant"]._update_available_quantity(p3, loc, 10)
+        self.env["stock.quant"]._update_available_quantity(p4, loc, 10)
+        self.assertEqual(p1.qty_available, 5.0)
+        self.assertEqual(p2.qty_available, 10.0)
+        self.assertEqual(p3.qty_available, 10.0)