diff --git a/modules/cart/src/Form/AddToCartForm.php b/modules/cart/src/Form/AddToCartForm.php
index d44c131..1b2e085 100644
--- a/modules/cart/src/Form/AddToCartForm.php
+++ b/modules/cart/src/Form/AddToCartForm.php
@@ -11,6 +11,7 @@ use Drupal\commerce_price\Resolver\ChainPriceResolverInterface;
 use Drupal\commerce_store\StoreContextInterface;
 use Drupal\Component\Datetime\TimeInterface;
 use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Form\FormStateInterface;
@@ -21,7 +22,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 /**
  * Provides the order item add to cart form.
  */
-class AddToCartForm extends ContentEntityForm {
+class AddToCartForm extends ContentEntityForm implements AddToCartFormInterface {
 
   /**
    * The cart manager.
@@ -59,20 +60,18 @@ class AddToCartForm extends ContentEntityForm {
   protected $chainPriceResolver;
 
   /**
-   * The form instance ID.
-   *
-   * Numeric counter used to ensure form ID uniqueness.
+   * The current user.
    *
-   * @var int
+   * @var \Drupal\Core\Session\AccountInterface
    */
-  protected static $formInstanceId = 0;
+  protected $currentUser;
 
   /**
-   * The current user.
+   * The form ID.
    *
-   * @var \Drupal\Core\Session\AccountInterface
+   * @var string
    */
-  protected $currentUser;
+  protected $formId;
 
   /**
    * Constructs a new AddToCartForm object.
@@ -105,8 +104,6 @@ class AddToCartForm extends ContentEntityForm {
     $this->storeContext = $store_context;
     $this->chainPriceResolver = $chain_price_resolver;
     $this->currentUser = $current_user;
-
-    self::$formInstanceId++;
   }
 
   /**
@@ -129,6 +126,14 @@ class AddToCartForm extends ContentEntityForm {
   /**
    * {@inheritdoc}
    */
+  public function setEntity(EntityInterface $entity) {
+    $this->entity = $entity;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getBaseFormId() {
     return $this->entity->getEntityTypeId() . '_' . $this->operation . '_form';
   }
@@ -137,16 +142,24 @@ class AddToCartForm extends ContentEntityForm {
    * {@inheritdoc}
    */
   public function getFormId() {
-    $form_id = $this->entity->getEntityTypeId();
-    if ($this->entity->getEntityType()->hasKey('bundle')) {
-      $form_id .= '_' . $this->entity->bundle();
-    }
-    if ($this->operation != 'default') {
-      $form_id = $form_id . '_' . $this->operation;
+    if (empty($this->formId)) {
+      $this->formId = $this->getBaseFormId();
+      /** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */
+      $order_item = $this->entity;
+      if ($purchased_entity = $order_item->getPurchasedEntity()) {
+        $this->formId .= '_' . $purchased_entity->getEntityTypeId() . '_' . $purchased_entity->id();
+      }
     }
-    $form_id .= '_' . self::$formInstanceId;
 
-    return $form_id . '_form';
+    return $this->formId;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setFormId($form_id) {
+    $this->formId = $form_id;
+    return $this;
   }
 
   /**
diff --git a/modules/cart/src/Form/AddToCartFormInterface.php b/modules/cart/src/Form/AddToCartFormInterface.php
new file mode 100644
index 0000000..5e415a8
--- /dev/null
+++ b/modules/cart/src/Form/AddToCartFormInterface.php
@@ -0,0 +1,28 @@
+<?php
+
+namespace Drupal\commerce_cart\Form;
+
+use Drupal\Core\Entity\ContentEntityFormInterface;
+
+/*
+ * Provides the add to cart form interface.
+ *
+ * Extends the regular interface to allow the form ID to be overriden.
+ * By default the form ID is suffixed with the order item's purchasable
+ * entity ID, to achieve uniqueness. Callers can replace that form ID with
+ * a more stable one, or to handle the case where the order item has no
+ * purchasable entity, but multiple form instances are still desired.
+ */
+interface AddToCartFormInterface extends ContentEntityFormInterface {
+
+  /**
+   * Sets the form ID.
+   *
+   * @param string $form_id
+   *   The form ID.
+   *
+   * @return $this
+   */
+  public function setFormId($form_id);
+
+}
diff --git a/modules/product/commerce_product.services.yml b/modules/product/commerce_product.services.yml
index ce5dd84..cca824d 100644
--- a/modules/product/commerce_product.services.yml
+++ b/modules/product/commerce_product.services.yml
@@ -5,7 +5,7 @@ services:
 
   commerce_product.lazy_builders:
     class: Drupal\commerce_product\ProductLazyBuilders
-    arguments: ['@entity_type.manager', '@entity.form_builder']
+    arguments: ['@entity_type.manager', '@form_builder']
 
   commerce_product.variation_field_renderer:
     class: Drupal\commerce_product\ProductVariationFieldRenderer
diff --git a/modules/product/src/ProductLazyBuilders.php b/modules/product/src/ProductLazyBuilders.php
index 195f0cd..768871a 100644
--- a/modules/product/src/ProductLazyBuilders.php
+++ b/modules/product/src/ProductLazyBuilders.php
@@ -4,6 +4,8 @@ namespace Drupal\commerce_product;
 
 use Drupal\Core\Entity\EntityFormBuilderInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Form\FormState;
 
 /**
  * Provides #lazy_builder callbacks.
@@ -18,23 +20,23 @@ class ProductLazyBuilders {
   protected $entityTypeManager;
 
   /**
-   * The entity form builder.
+   * The form builder.
    *
-   * @var \Drupal\Core\Entity\EntityFormBuilderInterface
+   * @var \Drupal\Core\Form\FormBuilderInterface
    */
-  protected $entityFormBuilder;
+  protected $formBuilder;
 
   /**
    * Constructs a new CartLazyBuilders object.
    *
    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
    *   The entity type manager.
-   * @param \Drupal\Core\Entity\EntityFormBuilderInterface $entity_form_builder
-   *   The entity form builder.
+   * @param \Drupal\Core\Form\FormBuilderInterface $form_builder
+   *   The form builder.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityFormBuilderInterface $entity_form_builder) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, FormBuilderInterface $form_builder) {
     $this->entityTypeManager = $entity_type_manager;
-    $this->entityFormBuilder = $entity_form_builder;
+    $this->formBuilder = $form_builder;
   }
 
   /**
@@ -61,14 +63,21 @@ class ProductLazyBuilders {
     }
 
     $order_item = $order_item_storage->createFromPurchasableEntity($default_variation);
-    $form_state_additions = [
+    /** @var \Drupal\commerce_cart\Form\AddToCartFormInterface $form_object */
+    $form_object = $this->entityTypeManager->getFormObject('commerce_order_item', 'add_to_cart');
+    $form_object->setEntity($order_item);
+    // The default form ID is based on the variation ID, but in this case the product ID is more reliable
+    // (the default variation might change between requests due to an availability change, for example).
+    $form_object->setFormId($form_object->getBaseFormId() . '_commerce_product_' . $product_id);
+    $form_state = (new FormState())->setFormState([
       'product' => $product,
       'view_mode' => $view_mode,
       'settings' => [
         'combine' => $combine,
       ],
-    ];
-    return $this->entityFormBuilder->getForm($order_item, 'add_to_cart', $form_state_additions);
+    ]);
+
+    return $this->formBuilder->buildForm($form_object, $form_state);
   }
 
 }
