diff --git a/vendor/magento/module-negotiable-quote/view/adminhtml/web/js/quote/quote-management.js b/vendor/magento/module-negotiable-quote/view/adminhtml/web/js/quote/quote-management.js
index 6059b0fedb6..b302b70e343 100644
--- a/vendor/magento/module-negotiable-quote/view/adminhtml/web/js/quote/quote-management.js
+++ b/vendor/magento/module-negotiable-quote/view/adminhtml/web/js/quote/quote-management.js
@@ -52,7 +52,11 @@ define([
             qty = parseInt(qty, 10);
 
             this.cachedItems.forEach((element) => {
-                if (element[updateKey] === productId) {
+                const matches = updateKey === 'id'
+                    ? parseInt(element[updateKey], 10) === parseInt(productId, 10)
+                    : element[updateKey] === productId;
+
+                if (matches) {
                     element.qty = qty;
                 }
             });
@@ -65,7 +69,7 @@ define([
             registry.get(this.dataSourceLocator)
                 .get('data.items')
                 .forEach((dataSourceItem, dataSourceItemIndex) => {
-                    if (parseInt(dataSourceItem.id, 10) === productId) {
+                    if (parseInt(dataSourceItem.id, 10) === parseInt(productId, 10)) {
                         registry.get(this.dataSourceLocator).set('data.items.' + dataSourceItemIndex + '.qty', qty);
                     }
                 });
diff --git a/vendor/magento/module-negotiable-quote-template/view/adminhtml/web/js/items-grid/columns/qty-input.js b/vendor/magento/module-negotiable-quote-template/view/adminhtml/web/js/items-grid/columns/qty-input.js
index 76a723786ef..cb9c4c63406 100644
--- a/vendor/magento/module-negotiable-quote-template/view/adminhtml/web/js/items-grid/columns/qty-input.js
+++ b/vendor/magento/module-negotiable-quote-template/view/adminhtml/web/js/items-grid/columns/qty-input.js
@@ -100,7 +100,10 @@ define([
                     .text(component.templateQtyOptions.maxQtyRangeError);
                 $(event.currentTarget).siblings(component.templateQtyOptions.maxQtyInputSelector).addClass('error');
             }
-            quoteManagement.updateItemQty(row.item_hash, qty, 'item_hash');
+            // Match on the stable quote-item id, not item_hash: a configuration change rotates the
+            // item_hash in cachedItems while the grid row keeps the old hash, so matching by hash
+            // would silently drop the qty edit. The id never changes on reconfiguration.
+            quoteManagement.updateItemQty(row.id, qty, 'id');
         },
 
         /**
