diff --git a/payment/src/Annotations/PaymentMethod.php b/payment/src/Annotations/PaymentMethod.php
index f4966a0..a365004 100644
--- a/payment/src/Annotations/PaymentMethod.php
+++ b/payment/src/Annotations/PaymentMethod.php
@@ -28,6 +28,17 @@ class PaymentMethod extends Plugin {
   public $active = TRUE;
 
   /**
+   * Whether executing a payment interferes with the payment type context.
+   *
+   * If payment execution interrupts the context's workflow, this must be TRUE.
+   * An example of an interruption is when the payer must be redirected
+   * off-site.
+   *
+   * @var bool
+   */
+  public $interrupts_payment_type_context = TRUE;
+
+  /**
    * The plugin ID.
    *
    * @var string
diff --git a/payment/src/Plugin/Payment/Method/BasicDerivative.php b/payment/src/Plugin/Payment/Method/BasicDerivative.php
index f9e6c7f..065e0c5 100644
--- a/payment/src/Plugin/Payment/Method/BasicDerivative.php
+++ b/payment/src/Plugin/Payment/Method/BasicDerivative.php
@@ -53,7 +53,7 @@ class BasicDerivative extends DerivativeBase implements ContainerDerivativeInter
    * {@inheritdoc}
    */
   public function getDerivativeDefinitions($base_plugin_definition) {
-    /** @var \Drupal\payment\Entity\PaymentMethodInterface[] $payment_methods */
+    /** @var \Drupal\payment\Entity\PaymentMethodConfigurationInterface[] $payment_methods */
     $payment_methods = $this->paymentMethodStorage->loadMultiple();
     foreach ($payment_methods as $payment_method) {
       if ($payment_method->getPluginId() == 'payment_basic') {
@@ -61,6 +61,7 @@ class BasicDerivative extends DerivativeBase implements ContainerDerivativeInter
         $configuration_plugin = $this->paymentMethodConfigurationManager->createInstance($payment_method->getPluginId(), $payment_method->getPluginConfiguration());
         $this->derivatives[$payment_method->id()] = array(
           'active' => $payment_method->status(),
+          'interrupts_payment_type_context' => FALSE,
           'label' => $configuration_plugin->getBrandLabel() ? $configuration_plugin->getBrandLabel() : $payment_method->label(),
           'message_text' => $configuration_plugin->getMessageText(),
           'message_text_format' => $configuration_plugin->getMessageTextFormat(),
diff --git a/payment/src/Plugin/Payment/Method/PaymentMethodInterface.php b/payment/src/Plugin/Payment/Method/PaymentMethodInterface.php
index 6ed2773..d70c6ec 100644
--- a/payment/src/Plugin/Payment/Method/PaymentMethodInterface.php
+++ b/payment/src/Plugin/Payment/Method/PaymentMethodInterface.php
@@ -21,10 +21,6 @@ interface PaymentMethodInterface extends PluginInspectionInterface, Configurable
   /**
    * Returns the form elements to configure payments.
    *
-   * $form_state['payment'] contains the payment that is added or edited. All
-   * payment-specific information should be added to it during element
-   * validation. The payment will be saved automatically.
-   *
    * @param array $form
    * @param array $form_state
    * @param \Drupal\payment\Entity\PaymentInterface $payment
diff --git a/payment/src/Plugin/Payment/MethodSelector/PaymentSelect.php b/payment/src/Plugin/Payment/MethodSelector/PaymentSelect.php
index db997e2..84b2143 100644
--- a/payment/src/Plugin/Payment/MethodSelector/PaymentSelect.php
+++ b/payment/src/Plugin/Payment/MethodSelector/PaymentSelect.php
@@ -6,6 +6,7 @@
 
 namespace Drupal\payment\Plugin\Payment\MethodSelector;
 
+use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\payment\Entity\PaymentInterface;
 
@@ -20,6 +21,11 @@ use Drupal\payment\Entity\PaymentInterface;
 class PaymentSelect extends PaymentMethodSelectorBase {
 
   /**
+   * The number of seconds a payment should remain stored.
+   */
+  const KEY_VALUE_TTL = 3600;
+
+  /**
    * {@inheritdoc}
    */
   public function formElements(array $form, array &$form_state, PaymentInterface $payment) {
@@ -98,6 +104,7 @@ class PaymentSelect extends PaymentMethodSelectorBase {
         }
         $element['select']['payment_method_plugin_id'] = array(
           '#ajax' => array(
+            'callback' => array($this, 'ajaxSubmit'),
             'effect' => 'fade',
             'event' => 'change',
             'trigger_as' => array(
@@ -130,8 +137,9 @@ class PaymentSelect extends PaymentMethodSelectorBase {
         '#id' => $this->getElementId($element, $form_state),
         '#type' => 'container',
       );
-
-      $element['payment_method_form'] = is_null($selected_payment_method) ? array() : $selected_payment_method->formElements($form, $form_state, $payment);
+      if ($selected_payment_method) {
+        $element['payment_method_form'] += $selected_payment_method->formElements($form, $form_state, $payment);
+      }
     }
 
     // The element itself has no input, but only its children, so mark it not
@@ -145,9 +153,10 @@ class PaymentSelect extends PaymentMethodSelectorBase {
    * Implements form #submit callback.
    */
   public function submit(array &$form, array &$form_state) {
-    $parents = array_slice($form_state['triggering_element']['#parents'], 0, -2);
-    $payment_method_plugin_id = NestedArray::getValue($form_state['values'], array_merge($parents, array('select', 'payment_method_plugin_id')));
-    $root_element = NestedArray::getValue($form, $parents);
+    $form_parents = array_slice($form_state['triggering_element']['#array_parents'], 0, -2);
+    $form_state_parents = array_slice($form_state['triggering_element']['#parents'], 0, -2);
+    $payment_method_plugin_id = NestedArray::getValue($form_state['values'], array_merge($form_state_parents, array('select', 'payment_method_plugin_id')));
+    $root_element = NestedArray::getValue($form, $form_parents);
     $payment_method_data = $this->getPaymentMethodData($root_element, $form_state);
     if ($payment_method_data['plugin_id'] != $payment_method_plugin_id) {
       $this->setPaymentMethodData($root_element, $form_state, $payment_method_plugin_id);
@@ -193,7 +202,7 @@ class PaymentSelect extends PaymentMethodSelectorBase {
    *   - plugin_configuration: An array with tThe payment method plugin's
    *     configuration.
    */
-  protected function getPaymentMethodData(array $element, array &$form_state) {
+  protected function getPaymentMethodData($element,  &$form_state) {
     return $form_state[$this->getPluginId()][$element['#name']]['payment_method_data'];
   }
 
@@ -210,6 +219,41 @@ class PaymentSelect extends PaymentMethodSelectorBase {
   }
 
   /**
+   * Retrieves the element's ID from the form's state.
+   *
+   * @param array $element
+   * @param array $form_state
+   *
+   * @return string
+   */
+  protected function getKeyValueKey(array $element, array &$form_state) {
+    return $form_state[$this->getPluginId()][$element['#name']]['key_value_key'];
+  }
+
+  /**
+   * Stores the payment temporarily, so it can be retrieved using the key/value key.
+   *
+   * @param array $element
+   * @param array $form_state
+   * @param \Drupal\payment\Entity\PaymentInterface $payment
+   */
+  protected function setKeyValueData(array $element, array &$form_state, PaymentInterface $payment) {
+    \Drupal::keyValueExpirable('payment.payment_method_selector.payment_select')->setWithExpire($this->getKeyValueKey($element, $form_state), $payment, static::KEY_VALUE_TTL);
+  }
+
+  /**
+   * Retrieves the temporarily stored payment.
+   *
+   * @param array $element
+   * @param array $form_state
+   *
+   * @return \Drupal\payment\Entity\PaymentInterface
+   */
+  protected function getKeyValueData(array $element, array &$form_state) {
+    return \Drupal::keyValueExpirable('payment.payment_method_selector.payment_select')->get($this->getKeyValueKey($element, $form_state));
+  }
+
+  /**
    * Check if the form's state has been initialized for an element.
    *
    * @param array $element
@@ -224,6 +268,8 @@ class PaymentSelect extends PaymentMethodSelectorBase {
       $plugin_id = $payment->getPaymentMethod() ? $payment->getPaymentMethod()->getPluginId() : NULL;
       $this->setPaymentMethodData($element, $form_state, $plugin_id, $plugin_configuration);
       $form_state[$this->getPluginId()][$element['#name']]['element_id'] = isset($element['#id']) ? $element['#id'] : drupal_html_id($this->getPluginId());
+      $form_state[$this->getPluginId()][$element['#name']]['key_value_key'] = Crypt::hmacBase64(REQUEST_TIME . mt_rand(), drupal_get_hash_salt() . \Drupal::service('private_key')->get());
+      $this->setKeyValueData($element, $form_state, $payment);
     }
   }
 }
diff --git a/payment/src/Tests/Plugin/Payment/MethodSelector/PaymentSelectWebTest.php b/payment/src/Tests/Plugin/Payment/MethodSelector/PaymentSelectWebTest.php
index 6f9acef..4f4870a 100644
--- a/payment/src/Tests/Plugin/Payment/MethodSelector/PaymentSelectWebTest.php
+++ b/payment/src/Tests/Plugin/Payment/MethodSelector/PaymentSelectWebTest.php
@@ -52,12 +52,13 @@ class PaymentSelectWebTest extends WebTestBase {
    * Tests the element.
    */
   protected function testElement() {
+    $path = 'payment_test-payment_method_selector-payment_select';
     $state = \Drupal::state();
     /** @var \Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface|\Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface $payment_method_manager */
     $payment_method_manager = Payment::methodManager();
 
     // Test the presence of default elements without available payment methods.
-    $this->drupalGet('payment_test-payment_method_selector-payment_select');
+    $this->drupalGet($path);
     $this->assertNoFieldByName('payment_method[select][payment_method_plugin_id]');
     $this->assertNoFieldByName('payment_method[select][change]', t('Choose payment method'));
     $this->assertText(t('There are no available payment methods.'));
@@ -65,7 +66,7 @@ class PaymentSelectWebTest extends WebTestBase {
     // Test the presence of default elements with one available payment method.
     $payment_method_1 = $this->createPaymentMethod();
     $payment_method_manager->clearCachedDefinitions();
-    $this->drupalGet('payment_test-payment_method_selector-payment_select');
+    $this->drupalGet($path);
     $this->assertNoFieldByName('payment_method[select][payment_method_plugin_id]');
     $this->assertNoFieldByName('payment_method[select][change]', t('Choose payment method'));
     $this->assertNoText(t('There are no available payment methods.'));
@@ -74,7 +75,7 @@ class PaymentSelectWebTest extends WebTestBase {
     // methods.
     $payment_method_2 = $this->createPaymentMethod();
     $payment_method_manager->clearCachedDefinitions();
-    $this->drupalGet('payment_test-payment_method_selector-payment_select');
+    $this->drupalGet($path);
     $this->assertFieldByName('payment_method[select][payment_method_plugin_id]');
     $this->assertFieldByName('payment_method[select][change]', t('Choose payment method'));
     $this->assertNoText(t('There are no available payment methods.'));
diff --git a/payment/tests/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorBaseUnitTest.php b/payment/tests/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorBaseUnitTest.php
index 29cfde7..bd68942 100644
--- a/payment/tests/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorBaseUnitTest.php
+++ b/payment/tests/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorBaseUnitTest.php
@@ -48,6 +48,8 @@ class PaymentMethodSelectorBaseUnitTest extends UnitTestCase {
 
   /**
    * {@inheritdoc}
+   *
+   * @covers ::__construct
    */
   public function setUp() {
     $this->currentUser = $this->getMock('\Drupal\Core\Session\AccountInterface');
diff --git a/payment_form/tests/src/Plugin/Field/FieldFormatter/PaymentFormUnitTest.php b/payment_form/tests/src/Plugin/Field/FieldFormatter/PaymentFormUnitTest.php
index 1e92fa9..ea330c2 100644
--- a/payment_form/tests/src/Plugin/Field/FieldFormatter/PaymentFormUnitTest.php
+++ b/payment_form/tests/src/Plugin/Field/FieldFormatter/PaymentFormUnitTest.php
@@ -100,11 +100,22 @@ class PaymentFormUnitTest extends UnitTestCase {
    * Tests viewElements().
    */
   public function testViewElements() {
+    $request_uri = $this->randomName();
+    $field_id = $this->randomName();
+
+    $this->request->expects($this->once())
+      ->method('getUri')
+      ->will($this->returnValue($request_uri));
+
     $payment_type = $this->getMockBuilder('\Drupal\payment_form\Plugin\Payment\Type\PaymentForm')
       ->disableOriginalConstructor()
       ->getMock();
     $payment_type->expects($this->once())
-      ->method('setFieldInstanceConfigId');
+      ->method('setFieldInstanceConfigId')
+      ->with($field_id);
+    $payment_type->expects($this->once())
+      ->method('setDestinationUrl')
+      ->with($request_uri);
 
     $payment = $this->getMockBuilder('\Drupal\payment\Entity\Payment')
       ->disableOriginalConstructor()
@@ -178,7 +189,6 @@ class PaymentFormUnitTest extends UnitTestCase {
       ->method('getIterator')
       ->will($this->returnValue($iterator));
 
-    $field_id = $this->randomName();
     $this->fieldDefinition->expects($this->once())
       ->method('getName')
       ->will($this->returnValue($field_id));
diff --git a/payment_reference/payment_reference.module b/payment_reference/payment_reference.module
index f1e92fe..2da5f42 100644
--- a/payment_reference/payment_reference.module
+++ b/payment_reference/payment_reference.module
@@ -23,18 +23,20 @@ function payment_reference_element_info() {
   $elements['payment_reference'] = array(
     // The ID of a payment as the default value.
     '#default_value' => NULL,
-    // The ID of the field instance config the element is used for.
-    '#field_instance_config_id' => NULL,
     '#input' => TRUE,
-    // The ID of the account that must own the payment.
-    '#owner_id' => NULL,
-    // Values are arrays with two keys:
-    // - plugin_id: the ID of the line item plugin instance.
-    // - plugin_configuration: the configuration of the line item plugin
-    //   instance.
-    '#payment_line_items_data' => array(),
-    '#payment_currency_code' => '',
+    // An array with IDs of the payment methods the payer is allowed to pay the
+    // payment with, or NULL to allow all.
+    '#limit_allowed_payment_method_ids' => NULL,
+    // The ID of the payment method selector plugin to use.
+    '#payment_method_selector_id' => NULL,
     '#process' => array(array('Drupal\payment_reference\Element\PaymentReference', 'process')),
+    // The ID of the queue category the element is used for.
+    // The payment that must be made if none are available in the queue yet. It
+    // must be an instance of \Drupal\payment\Entity\PaymentInterface.
+    '#prototype_payment' => NULL,
+    '#queue_category_id' => NULL,
+    // The ID of the account that must own the payment.
+    '#queue_owner_id' => NULL,
     '#theme_wrappers' => array('form_element'),
     '#value_callback' => 'payment_reference_element_payment_reference_value',
   );
@@ -113,7 +115,7 @@ function payment_reference_entity_field_access($operation, FieldDefinitionInterf
  * https://drupal.org/node/2040559 has been fixed.
  */
 function payment_reference_element_payment_reference_value(array $element, $input, array &$form_state) {
-  $payment_ids = PaymentReference::queue()->loadPaymentIds($element['#field_instance_config_id'], $element['#owner_id']);
+  $payment_ids = PaymentReference::queue()->loadPaymentIds($element['#queue_category_id'], $element['#queue_owner_id']);
   if ($payment_ids) {
     return reset($payment_ids);
   }
diff --git a/payment_reference/payment_reference.services.yml b/payment_reference/payment_reference.services.yml
index 405de6c..95d0184 100644
--- a/payment_reference/payment_reference.services.yml
+++ b/payment_reference/payment_reference.services.yml
@@ -1,4 +1,7 @@
 services:
+  payment_reference.factory:
+    class: Drupal\payment_reference\Factory
+    arguments: ['@entity.manager', '@plugin.manager.payment.line_item']
   payment_reference.queue:
     arguments: ['payment_reference', '@database', '@module_handler', '@event_dispatcher', '@plugin.manager.payment.status']
     class: Drupal\payment\Queue
\ No newline at end of file
diff --git a/payment_reference/src/Element/PaymentReference.php b/payment_reference/src/Element/PaymentReference.php
index 5e1810b..c0e11ea 100644
--- a/payment_reference/src/Element/PaymentReference.php
+++ b/payment_reference/src/Element/PaymentReference.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\payment_reference\Element;
 
+use Drupal\payment\Entity\PaymentInterface;
 use Drupal\payment\Payment;
 use Drupal\payment_reference\PaymentReference as PaymentReferenceServiceWrapper;
 
@@ -22,26 +23,32 @@ class PaymentReference {
   public static function process(array $element, array &$form_state, array $form) {
     // Validate the element's configuration.
     if (!is_int($element['#default_value']) && !is_null($element['#default_value'])) {
-      throw new \InvalidArgumentException('The default value must be an integer or NULL, but ' . gettype($element['#default_value']) . ' was given.');
+      throw new \InvalidArgumentException('#default_value must be an integer or NULL, but ' . gettype($element['#default_value']) . ' was given.');
     }
-    if (!is_int($element['#owner_id'])) {
-      throw new \InvalidArgumentException('The owner ID must be an integer, but ' . gettype($element['#owner_id']) . ' was given.');
+    if (!is_null($element['#limit_allowed_payment_method_ids']) && !is_array($element['#limit_allowed_payment_method_ids'])) {
+      throw new \InvalidArgumentException('#limit_allowed_payment_method_ids must be an array or NULL, but ' . gettype($element['#limit_allowed_payment_method_ids']) . ' was given.');
     }
-    if (!is_string($element['#payment_currency_code'])) {
-      throw new \InvalidArgumentException('The currency code must be a string, but ' . gettype($element['#payment_currency_code']) . ' was given.');
+    if (!($element['#prototype_payment'] instanceof PaymentInterface)) {
+      throw new \InvalidArgumentException('#prototype_payment must implement \Drupal\payment\Entity\PaymentInterface.');
     }
-    if (!is_string($element['#field_instance_config_id'])) {
-      throw new \InvalidArgumentException('The field instance config ID must be a string, but ' . gettype($element['#field_instance_config_id']) . ' was given.');
+    if (!is_string($element['#payment_method_selector_id'])) {
+      throw new \InvalidArgumentException('#payment_method_selector_id must be a string, but ' . gettype($element['#payment_method_selector_id']) . ' was given.');
+    }
+    if (!is_string($element['#queue_category_id'])) {
+      throw new \InvalidArgumentException('#queue_category_id must be a string, but ' . gettype($element['#queue_category_id']) . ' was given.');
+    }
+    if (!is_int($element['#queue_owner_id'])) {
+      throw new \InvalidArgumentException('#queue_owner_id must be an integer, but ' . gettype($element['#queue_owner_id']) . ' was given.');
     }
 
     // Find the default payment to use.
-    $pid = $element['#default_value'];
-    if (!$pid) {
-      $pids = PaymentReferenceServiceWrapper::queue()->loadPaymentIds($element['#field_instance_config_id'], $element['#owner_id']);
-      $pid = reset($pids);
+    $payment_id = $element['#default_value'];
+    if (!$payment_id) {
+      $payment_ids = PaymentReferenceServiceWrapper::queue()->loadPaymentIds($element['#queue_category_id'], $element['#queue_owner_id']);
+      $payment_id = reset($payment_ids);
     }
     // Form API considers an empty string to be an empty value, but not NULL.
-    $element['#value'] = $pid ? $pid : '';
+    $element['#value'] = $payment_id ? $payment_id : '';
 
     // AJAX.
     $ajax_wrapper_id = drupal_html_id('payment_reference-' . $element['#name']);
@@ -53,47 +60,52 @@ class PaymentReference {
       'type' => 'setting',
         'data' => array(
           'PaymentReferencePaymentAvailable' => array(
-            $ajax_wrapper_id => !empty($pid),
+            $ajax_wrapper_id => !empty($payment_id),
           ),
         ),
       ),
     );
 
-    // Payment information.
-    $element['payment'] = array(
-      '#empty' => t('There are no line items.'),
-      '#header' => array(t('Amount'), t('Status'), t('Last updated')),
-      '#type' => 'table',
-    );
-    if (!$pid) {
-      $amount = 0;
-      foreach ($element['#payment_line_items_data'] as $line_item_data) {
-        $line_item = Payment::lineItemManager()->createInstance($line_item_data['plugin_id'], $line_item_data['plugin_configuration']);
-        $amount += $line_item->getTotalAmount();
-      }
-      /** @var \Drupal\currency\Entity\CurrencyInterface $currency */
-      $currency = entity_load('currency', $element['#payment_currency_code']);
-      $element['payment'][0]['amount'] = array(
-        '#markup' => $currency->formatAmount($amount),
+    // There are no queued payments, so display a payment method selection and
+    // configuration form.
+    if (!$payment_id) {
+      /** @var \Drupal\payment\Entity\PaymentInterface $payment */
+      $payment = clone $element['#prototype_payment'];
+      $element['line_items'] = array(
+        '#payment' => $payment,
+        '#type' => 'payment_line_items_display',
       );
+      $payment_method_selector = Payment::methodSelectorManager()->createInstance($element['#payment_method_selector_id']);
+      if (!is_null($element['#limit_allowed_payment_method_ids'])) {
+        $payment_method_selector->setAllowedPaymentMethods($element['#limit_allowed_payment_method_ids']);
+      }
+      $element['payment_method'] = $payment_method_selector->formElements(array(), $form_state, $payment);
+
       $element['payment'][0]['add'] = array(
         '#attributes' => array(
           'colspan' => 2,
         ),
         '#markup' => t('<a href="@url" target="_blank">Add a new payment</a> (opens in a new window)', array(
           '@url' => \Drupal::urlGenerator()->generateFromRoute('payment_reference.pay', array(
-            'field_instance_config' => $element['#field_instance_config_id'],
-          )),
+              // @todo This form element pretends to be implementation-agnostic,
+              // but it does depend on a Payment Reference route. Fix this.
+              'field_instance_config' => $element['#queue_category_id'],
+            )),
         )),
       );
     }
+    // There is a queued payment, so display its information.
     else {
       /** @var \Drupal\payment\Entity\PaymentInterface $payment */
-      $payment = entity_load('payment', $pid);
-      /** @var \Drupal\currency\Entity\CurrencyInterface $currency */
-      $currency = entity_load('currency', $payment->getCurrencyCode());
+      $payment = entity_load('payment', $payment_id);
+      $currency = $payment->getCurrency();
       $status = $payment->getStatus();
       $status_definition = $status->getPluginDefinition();
+      $element['payment'] = array(
+        '#empty' => t('There are no line items.'),
+        '#header' => array(t('Amount'), t('Status'), t('Last updated')),
+        '#type' => 'table',
+      );
       $element['payment'][0]['amount'] = array(
         '#markup' => $currency->formatAmount($payment->getAmount()),
       );
diff --git a/payment_reference/src/Factory.php b/payment_reference/src/Factory.php
new file mode 100644
index 0000000..3b62760
--- /dev/null
+++ b/payment_reference/src/Factory.php
@@ -0,0 +1,67 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment_reference\Factory.
+ */
+
+namespace Drupal\payment_reference;
+
+use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\field\FieldInstanceConfigInterface;
+use Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface;
+
+/**
+ * Provides a payment factory service.
+ */
+class Factory implements FactoryInterface {
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface
+   */
+  protected $entityManager;
+
+  /**
+   * The payment line item manager.
+   *
+   * @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface
+   */
+  protected $paymentLineItemManager;
+
+  /**
+   * Constructs a new class instance.
+   *
+   * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
+   *   The entity manager.
+   * @param \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface $payment_line_item_manager
+   *   The payment line item manager.
+   */
+  public function __construct(EntityManagerInterface $entity_manager, PaymentLineItemManagerInterface $payment_line_item_manager) {
+    $this->entityManager = $entity_manager;
+    $this->paymentLineItemManager = $payment_line_item_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createPayment(FieldInstanceConfigInterface $field_instance_config) {
+    /** @var \Drupal\payment\Entity\PaymentInterface $payment */
+    $payment = $this->entityManager
+      ->getStorage('payment')
+      ->create(array(
+        'bundle' => 'payment_reference',
+      ));
+    /** @var \Drupal\payment_reference\Plugin\Payment\Type\PaymentReference $payment_type */
+    $payment_type = $payment->getPaymentType();
+    $payment_type->setFieldInstanceConfigId($field_instance_config->id());
+    $payment->setCurrencyCode($field_instance_config->getSetting('currency_code'));
+    foreach ($field_instance_config->getSetting('line_items_data') as $line_item_data) {
+      $line_item = $this->paymentLineItemManager->createInstance($line_item_data['plugin_id'], $line_item_data['plugin_configuration']);
+      $payment->setLineItem($line_item);
+    }
+
+    return $payment;
+  }
+}
diff --git a/payment_reference/src/FactoryInterface.php b/payment_reference/src/FactoryInterface.php
new file mode 100644
index 0000000..e8f689d
--- /dev/null
+++ b/payment_reference/src/FactoryInterface.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment_reference\FactoryInterface.
+ */
+
+namespace Drupal\payment_reference;
+
+use Drupal\field\FieldInstanceConfigInterface;
+
+/**
+ * Defines a payment factory service.
+ */
+interface FactoryInterface {
+
+  /**
+   * Creates a payment for a field instance configuration entity.
+   *
+   * @param \Drupal\field\FieldInstanceConfigInterface
+   *
+   * @return \Drupal\payment\Entity\PaymentInterface
+   */
+  public function createPayment(FieldInstanceConfigInterface $field_instance_config);
+}
diff --git a/payment_reference/src/PaymentReference.php b/payment_reference/src/PaymentReference.php
index 97969d9..a5ef287 100644
--- a/payment_reference/src/PaymentReference.php
+++ b/payment_reference/src/PaymentReference.php
@@ -13,6 +13,15 @@ namespace Drupal\payment_reference;
 class PaymentReference {
 
   /**
+   * Returns the payment factory.
+   *
+   * @return \Drupal\payment_reference\FactoryInterface
+   */
+  public static function factory() {
+    return \Drupal::service('payment_reference.factory');
+  }
+
+  /**
    * Returns the payment reference queue.
    *
    * @return \Drupal\payment\QueueInterface
diff --git a/payment_reference/src/Plugin/Field/FieldWidget/PaymentReference.php b/payment_reference/src/Plugin/Field/FieldWidget/PaymentReference.php
index 04ffef2..636806f 100644
--- a/payment_reference/src/Plugin/Field/FieldWidget/PaymentReference.php
+++ b/payment_reference/src/Plugin/Field/FieldWidget/PaymentReference.php
@@ -7,12 +7,14 @@
 
 namespace Drupal\payment_reference\Plugin\Field\FieldWidget;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Field\WidgetBase;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\field\FieldInstanceConfigInterface;
+use Drupal\payment_reference\FactoryInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -31,6 +33,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 class PaymentReference extends WidgetBase implements ContainerFactoryPluginInterface {
 
   /**
+   * The config factory.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface
+   */
+  protected $configFactory;
+
+  /**
    * The current user.
    *
    * @var \Drupal\Core\Session\AccountInterface
@@ -38,6 +47,13 @@ class PaymentReference extends WidgetBase implements ContainerFactoryPluginInter
   protected $currentUser;
 
   /**
+   * The payment reference factory.
+   *
+   * @var \Drupal\payment_reference\FactoryInterface
+   */
+  protected $paymentFactory;
+
+  /**
    * Constructs a new class instance.
    *
    * @param array $plugin_id
@@ -48,19 +64,25 @@ class PaymentReference extends WidgetBase implements ContainerFactoryPluginInter
    *   The definition of the field to which the widget is associated.
    * @param array $settings
    *   The widget settings.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
    * @param \Drupal\Core\Session\AccountInterface $current_user
    *   The current user.
+   * @param \Drupal\payment_reference\FactoryInterface $payment_factory
+   *   The payment reference factory.
    */
-  public function __construct($plugin_id, array $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, AccountInterface $current_user) {
+  public function __construct($plugin_id, array $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, ConfigFactoryInterface $config_factory, AccountInterface $current_user, FactoryInterface $payment_factory) {
     parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings);
+    $this->configFactory = $config_factory;
     $this->currentUser = $current_user;
+    $this->paymentFactory = $payment_factory;
   }
 
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    return new static($plugin_id, $plugin_definition, $configuration['field_definition'], $configuration['settings'], $container->get('current_user'));
+    return new static($plugin_id, $plugin_definition, $configuration['field_definition'], $configuration['settings'], $container->get('config.factory'), $container->get('current_user'), $container->get('payment_reference.factory'));
   }
 
   /**
@@ -71,13 +93,16 @@ class PaymentReference extends WidgetBase implements ContainerFactoryPluginInter
       throw new \RuntimeException('This widget can only be used on configurable fields.');
     }
 
+    $config = $this->configFactory->get('payment_reference.payment_type');
+    $payment = $this->paymentFactory->createPayment($this->fieldDefinition);
     $element['payment_id'] = array(
       '#default_value' => isset($items[$delta]) ? $items[$delta]->target_id : NULL,
-      '#field_instance_config_id' => $this->fieldDefinition->id(),
+      '#limit_allowed_payment_method_ids' => $config->get('limit_allowed_payment_methods') ? $config->get('allowed_payment_method_ids') : NULL,
+      '#payment_method_selector_id' => $config->get('payment_method_selector_id'),
+      '#prototype_payment' => $payment,
+      '#queue_category_id' => $this->fieldDefinition->id(),
       // The requested user account may contain a string numeric ID.
-      '#owner_id' => (int) $this->currentUser->id(),
-      '#payment_line_items_data' => $this->getFieldSetting('line_items_data'),
-      '#payment_currency_code' => $this->getFieldSetting('currency_code'),
+      '#queue_owner_id' => (int) $this->currentUser->id(),
       '#required' => $this->fieldDefinition->isRequired(),
       '#type' => 'payment_reference',
     );
diff --git a/payment_reference/src/Plugin/Payment/Type/PaymentReference.php b/payment_reference/src/Plugin/Payment/Type/PaymentReference.php
index 13b293a..992fe43 100644
--- a/payment_reference/src/Plugin/Payment/Type/PaymentReference.php
+++ b/payment_reference/src/Plugin/Payment/Type/PaymentReference.php
@@ -104,16 +104,22 @@ class PaymentReference extends PaymentTypeBase implements ContainerFactoryPlugin
    * {@inheritdoc}
    */
   protected function doResumeContext() {
-    $url = $this->urlGenerator->generateFromRoute('payment_reference.resume_context', array(
-      'payment' => $this->getPayment()->id(),
-    ), array(
-      'absolute' => TRUE,
-    ));
-    $response = new RedirectResponse($url);
-    $listener = function(FilterResponseEvent $event) use ($response) {
-      $event->setResponse($response);
-    };
-    $this->eventDispatcher->addListener(KernelEvents::RESPONSE, $listener, 999);
+    // If the payment method does not interrupt the payment type context, the
+    // payer is still in the original context and we do not need to redirect
+    // them back.
+    $payment_method_definition = $this->getPayment()->getPaymentMethod()->getPluginDefinition();
+    if ($payment_method_definition['interrupts_payment_type_context']) {
+      $url = $this->urlGenerator->generateFromRoute('payment_reference.resume_context', array(
+        'payment' => $this->getPayment()->id(),
+      ), array(
+        'absolute' => TRUE,
+      ));
+      $response = new RedirectResponse($url);
+      $listener = function(FilterResponseEvent $event) use ($response) {
+        $event->setResponse($response);
+      };
+      $this->eventDispatcher->addListener(KernelEvents::RESPONSE, $listener, 999);
+    }
   }
 
   /**
diff --git a/payment_reference/src/Tests/FactoryUnitTest.php b/payment_reference/src/Tests/FactoryUnitTest.php
new file mode 100644
index 0000000..442baba
--- /dev/null
+++ b/payment_reference/src/Tests/FactoryUnitTest.php
@@ -0,0 +1,141 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment_reference\Tests\FactoryUnitTest.
+ */
+
+namespace Drupal\payment_reference\Tests;
+
+use Drupal\payment_reference\Factory;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\payment_reference\Factory
+ */
+class FactoryUnitTest extends UnitTestCase {
+
+  /**
+   * The entity manager used for testing.
+   *
+   * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $entityManager;
+
+  /**
+   * The payment line item manager used for testing.
+   *
+   * @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $paymentLineItemManager;
+
+  /**
+   * The factory under test.
+   *
+   * @var \Drupal\payment_reference\Factory
+   */
+  protected $factory;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'description' => '',
+      'name' => '\Drupal\payment_reference\Factory unit test',
+      'group' => 'Payment Reference Field',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    $this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
+
+    $this->paymentLineItemManager = $this->getMock('\Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface');
+
+    $this->factory = new Factory($this->entityManager, $this->paymentLineItemManager);
+  }
+
+  /**
+   * @covers ::createPayment
+   */
+  public function testCreatePayment() {
+    $currency_code = $this->randomName();
+    $field_instance_config_id = $this->randomName();
+
+    $payment_type = $this->getMockBuilder('\Drupal\payment_reference\Plugin\Payment\Type\PaymentReference')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $payment_type->expects($this->once())
+      ->method('setFieldInstanceConfigId')
+      ->with($field_instance_config_id);
+
+    $payment = $this->getMockBuilder('\Drupal\payment\Entity\Payment')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $payment->expects($this->once())
+      ->method('setCurrencyCode')
+      ->with($currency_code);
+    $payment->expects($this->once())
+      ->method('getPaymentType')
+      ->will($this->returnValue($payment_type));
+
+    $payment_storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
+    $payment_storage->expects($this->once())
+      ->method('create')
+      ->with(array(
+        'bundle' => 'payment_reference',
+      ))
+      ->will($this->returnValue($payment));
+
+    $this->entityManager->expects($this->once())
+      ->method('getStorage')
+      ->with('payment')
+      ->will($this->returnValue($payment_storage));
+
+    $line_item_a = $this->getMock('\Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface');
+    $line_item_plugin_id_a = $this->randomName();
+    $line_item_plugin_configuration_a = array(
+      'foo' => $this->randomName(),
+    );
+    $line_item_b = $this->getMock('\Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface');
+    $line_item_plugin_id_b = $this->randomName();
+    $line_item_plugin_configuration_b = array(
+      'bar' => $this->randomName(),
+    );
+
+    $field_instance_config = $this->getMock('\Drupal\field\FieldInstanceConfigInterface');
+    $field_instance_config->expects($this->once())
+      ->method('id')
+      ->will($this->returnValue($field_instance_config_id));
+    $map = array(
+      array('currency_code', $currency_code),
+      array('line_items_data', array(
+        array(
+          'plugin_configuration' => $line_item_plugin_configuration_a,
+          'plugin_id' => $line_item_plugin_id_a,
+        ),
+        array(
+          'plugin_configuration' => $line_item_plugin_configuration_b,
+          'plugin_id' => $line_item_plugin_id_b,
+        ),
+      )),
+    );
+    $field_instance_config->expects($this->exactly(2))
+      ->method('getSetting')
+      ->will($this->returnValueMap($map));
+
+    $this->paymentLineItemManager->expects($this->at(0))
+      ->method('createInstance')
+      ->with($line_item_plugin_id_a, $line_item_plugin_configuration_a)
+      ->will($this->returnValue($line_item_a));
+    $this->paymentLineItemManager->expects($this->at(1))
+      ->method('createInstance')
+      ->with($line_item_plugin_id_b, $line_item_plugin_configuration_b)
+      ->will($this->returnValue($line_item_b));
+
+    $this->assertSame(spl_object_hash($payment), spl_object_hash($this->factory->createPayment($field_instance_config)));
+  }
+}
diff --git a/payment_reference/tests/src/PaymentReferenceUnitTest.php b/payment_reference/tests/src/PaymentReferenceUnitTest.php
index 9d33f1d..23eb058 100644
--- a/payment_reference/tests/src/PaymentReferenceUnitTest.php
+++ b/payment_reference/tests/src/PaymentReferenceUnitTest.php
@@ -12,7 +12,7 @@ use Drupal\Tests\UnitTestCase;
 use Symfony\Component\DependencyInjection\Container;
 
 /**
- * Tests \Drupal\payment_reference\PaymentReference.
+ * @coversDefaultClass \Drupal\payment_reference\PaymentReference
  */
 class PaymentReferenceUnitTest extends UnitTestCase {
 
@@ -28,9 +28,9 @@ class PaymentReferenceUnitTest extends UnitTestCase {
   }
 
   /**
-   * Tests lineItemManager().
+   * @covers ::queue
    */
-  public function testLineItemManager() {
+  public function testQueue() {
     $container = new Container();
     $queue = $this->getMock('\Drupal\payment\QueueInterface');
     $container->set('payment_reference.queue', $queue);
@@ -38,4 +38,15 @@ class PaymentReferenceUnitTest extends UnitTestCase {
     $this->assertSame($queue, PaymentReference::queue());
   }
 
+  /**
+   * @covers ::factory
+   */
+  public function testFactory() {
+    $container = new Container();
+    $factory = $this->getMock('\Drupal\payment\FactoryInterface');
+    $container->set('payment_reference.factory', $factory);
+    \Drupal::setContainer($container);
+    $this->assertSame($factory, PaymentReference::factory());
+  }
+
 }
diff --git a/payment_reference/tests/src/Plugin/Field/FieldWidget/PaymentReferenceUnitTest.php b/payment_reference/tests/src/Plugin/Field/FieldWidget/PaymentReferenceUnitTest.php
index 1f46a43..b9c3bdb 100644
--- a/payment_reference/tests/src/Plugin/Field/FieldWidget/PaymentReferenceUnitTest.php
+++ b/payment_reference/tests/src/Plugin/Field/FieldWidget/PaymentReferenceUnitTest.php
@@ -8,6 +8,7 @@
 
 namespace Drupal\payment_reference\Tests\Plugin\Field\FieldWidget;
 
+use Drupal\payment_reference\Plugin\Field\FieldWidget\PaymentReference;
 use Drupal\Tests\UnitTestCase;
 
 /**
@@ -16,6 +17,13 @@ use Drupal\Tests\UnitTestCase;
 class PaymentReferenceUnitTest extends UnitTestCase {
 
   /**
+   * The config factory used for testing.
+   *
+   * @var \Drupal\Core\Config\ConfigFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $configFactory;
+
+  /**
    * A user account used for testing.
    *
    * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -30,6 +38,13 @@ class PaymentReferenceUnitTest extends UnitTestCase {
   protected $fieldInstanceConfig;
 
   /**
+   * The payment reference factory used for testing.
+   *
+   * @var \Drupal\payment_reference\FactoryInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $paymentFactory;
+
+  /**
    * The field widget plugin under test.
    *
    * @var \Drupal\payment_reference\Plugin\Field\FieldWidget\PaymentReference|\PHPUnit_Framework_MockObject_MockObject
@@ -51,44 +66,68 @@ class PaymentReferenceUnitTest extends UnitTestCase {
    * {@inheritdoc}
    */
   protected function setUp() {
+    $this->configFactory = $this->getMock('\Drupal\Core\Config\ConfigFactoryInterface');
+
     $this->fieldInstanceConfig = $this->getMock('\Drupal\field\FieldInstanceConfigInterface');
 
     $this->currentUser = $this->getMock('\Drupal\Core\Session\AccountInterface');
 
-    $this->widget = $this->getMockBuilder('\Drupal\payment_reference\Plugin\Field\FieldWidget\PaymentReference')
-      ->setConstructorArgs(array($this->randomName(), array(), $this->fieldInstanceConfig, array(), $this->currentUser))
-      ->setMethods(array('getFieldSetting'))
-      ->getMock();
+    $this->paymentFactory = $this->getMock('\Drupal\payment_reference\FactoryInterface');
+
+    $plugin_id = $this->randomName();
+    $plugin_definition = array();
+    $settings = array();
+    $this->widget = new PaymentReference($plugin_id, $plugin_definition, $this->fieldInstanceConfig, $settings, $this->configFactory, $this->currentUser, $this->paymentFactory);
   }
 
   /**
    * Tests formElement().
    */
   public function testFormElement() {
+    $field_instance_config_id = $this->randomName();
+    $required = TRUE;
+
+    $this->fieldInstanceConfig->expects($this->once())
+      ->method('id')
+      ->will($this->returnValue($field_instance_config_id));
     $this->fieldInstanceConfig->expects($this->once())
       ->method('isRequired')
-      ->will($this->returnValue(TRUE));
+      ->will($this->returnValue($required));
 
     $user_id = 2;
     $this->currentUser->expects($this->exactly(1))
       ->method('id')
       ->will($this->returnValue($user_id));
 
-    $currency_code = 'EUR';
-    $line_items_data = array(
-      array(
-        'plugin_configuration' => array(),
-        'plugin_id' => $this->randomName(),
-      ),
-    );
+    $allowed_payment_method_ids = array($this->randomName());
+    $payment_method_selector_id = $this->randomName();
+
+    $config = $this->getMockBuilder('\Drupal\Core\Config\Config')
+      ->disableOriginalConstructor()
+      ->getMock();
     $map = array(
-      array('currency_code', $currency_code),
-      array('line_items_data', $line_items_data),
+      array('limit_allowed_payment_methods', TRUE),
+      array('allowed_payment_method_ids', $allowed_payment_method_ids),
+      array('payment_method_selector_id', $payment_method_selector_id),
     );
-    $this->widget->expects($this->exactly(2))
-      ->method('getFieldSetting')
+    $config->expects($this->exactly(3))
+      ->method('get')
       ->will($this->returnValueMap($map));
 
+    $this->configFactory->expects($this->any())
+      ->method('get')
+      ->with('payment_reference.payment_type')
+      ->will($this->returnValue($config));
+
+    $payment = $this->getMockBuilder('\Drupal\payment\Entity\Payment')
+      ->disableOriginalConstructor()
+      ->getMock();
+
+    $this->paymentFactory->expects($this->once())
+      ->method('createPayment')
+      ->with($this->fieldInstanceConfig)
+      ->will($this->returnValue($payment));
+
     $items = $this->getMockBuilder('\Drupal\Core\Field\FieldItemList')
       ->disableOriginalConstructor()
       ->getMock();
@@ -96,9 +135,13 @@ class PaymentReferenceUnitTest extends UnitTestCase {
     $form = array();
     $form_state = array();
     $element = $this->widget->formElement($items, 3, array(), $form, $form_state);
-    $this->assertSame($element['payment_id']['#owner_id'], $user_id);
-    $this->assertSame($element['payment_id']['#payment_currency_code'], $currency_code);
-    $this->assertSame($element['payment_id']['#payment_line_items_data'], $line_items_data);
+    $this->assertSame($allowed_payment_method_ids, $element['payment_id']['#limit_allowed_payment_method_ids']);
+    $this->assertSame($payment, $element['payment_id']['#prototype_payment']);
+    $this->assertSame($payment_method_selector_id, $element['payment_id']['#payment_method_selector_id']);
+    $this->assertSame($field_instance_config_id, $element['payment_id']['#queue_category_id']);
+    $this->assertSame($user_id, $element['payment_id']['#queue_owner_id']);
+    $this->assertSame($required, $element['payment_id']['#required']);
+    $this->assertSame('payment_reference', $element['payment_id']['#type']);
   }
 
 }
diff --git a/payment_reference_test/src/PaymentReferenceElement.php b/payment_reference_test/src/PaymentReferenceElement.php
index cef0454..45616d0 100644
--- a/payment_reference_test/src/PaymentReferenceElement.php
+++ b/payment_reference_test/src/PaymentReferenceElement.php
@@ -27,15 +27,10 @@ class PaymentReferenceElement implements FormInterface {
    */
   public function buildForm(array $form, array &$form_state) {
     $form['payment_reference'] = array(
-      // The ID of the field instance the element is used for.
-      '#field_instance_config_id' => 'payment_reference_test_payment_reference_element',
-      // The ID of the account that must own the payment.
-      '#owner_id' => 2,
-      // An array of
-      // \Drupal\payment\Plugin\payment\line_item\PaymentLineItemInterface
-      // instances.
-      '#payment_line_items' => Generate::createPaymentLineItems(),
-      '#payment_currency_code' => 'EUR',
+      '#prototype_payment' => Generate::createPayment(2),
+      '#payment_method_selector_id' => 'payment_select',
+      '#queue_category_id' => 'payment_reference_test_payment_reference_element',
+      '#queue_owner_id' => 2,
       '#required' => TRUE,
       '#title' => 'Foo',
       '#type' => 'payment_reference',
