diff --git a/addons/mrp/models/product.py b/addons/mrp/models/product.py
index 535c7778f7655c0a6f5733acf7f5323bedbc6619..4b9d469793c27b89b9aa27c8ff087957466da288 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
@@ -213,20 +214,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 85ef81075203835256a39f3bac7ccc76e327b064..e7c71ebbba843b43a2a30acb8628cd302833bf3d 100644
--- a/addons/mrp/tests/common.py
+++ b/addons/mrp/tests/common.py
@@ -208,3 +208,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 4c8d7f3b0a99fb5dd108cefabc3c5122f4e59a9d..d0e8e46601a25a8d45ed73fcfc7e9ea8f358eb18 100644
--- a/addons/mrp/tests/test_bom.py
+++ b/addons/mrp/tests/test_bom.py
@@ -1082,3 +1082,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)