diff --git a/modules/payment_form/src/Entity/Payment/PaymentForm.php b/modules/payment_form/src/Entity/Payment/PaymentForm.php
index a231ac2..d3b8b2c 100644
--- a/modules/payment_form/src/Entity/Payment/PaymentForm.php
+++ b/modules/payment_form/src/Entity/Payment/PaymentForm.php
@@ -8,6 +8,7 @@
 namespace Drupal\payment_form\Entity\Payment;
 
 use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\StringTranslation\TranslationInterface;
@@ -127,4 +128,13 @@ class PaymentForm extends ContentEntityForm {
     return $actions;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function copyFormValuesToEntity(EntityInterface $entity, array $form, FormStateInterface $form_state) {
+    // Remove this override once https://drupal.org/node/2409143 has been fixed.
+    $this->getFormDisplay($form_state)
+      ->extractFormValues($entity, $form, $form_state);
+  }
+
 }
diff --git a/modules/payment_test/src/Plugin/Field/FieldType/MockPluginBagItem.php b/modules/payment_test/src/Plugin/Field/FieldType/MockPluginBagItem.php
new file mode 100644
index 0000000..49d58d8
--- /dev/null
+++ b/modules/payment_test/src/Plugin/Field/FieldType/MockPluginBagItem.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment_test\Plugin\Field\FieldType\PluginBagItem.
+ */
+
+namespace Drupal\payment_test\Plugin\Field\FieldType;
+
+use Drupal\payment\Plugin\Field\FieldType\PluginBagItemBase;
+use Drupal\payment_test\Plugin\PluginTest\MockManager;
+
+/**
+ * Provides a plugin bag field item for testing.
+ *
+ * @FieldType(
+ *   id = "payment_test_plugin_bag",
+ *   label = @Translation("Plugin bag")
+ * )
+ */
+class MockPluginBagItem extends PluginBagItemBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPluginManager() {
+    return new MockManager();
+  }
+
+}
diff --git a/modules/payment_test/src/Plugin/PluginTest/MockConfigurablePlugin.php b/modules/payment_test/src/Plugin/PluginTest/MockConfigurablePlugin.php
new file mode 100644
index 0000000..1f47741
--- /dev/null
+++ b/modules/payment_test/src/Plugin/PluginTest/MockConfigurablePlugin.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment_test\Plugin\PluginTest\MockPlugin.
+ */
+
+namespace Drupal\payment_test\Plugin\PluginTest;
+
+use Drupal\Component\Plugin\ConfigurablePluginInterface;
+use Drupal\Core\Plugin\PluginBase;
+
+/**
+ * Provides a configurable mock plugin.
+ */
+class MockConfigurablePlugin extends PluginBase implements ConfigurablePluginInterface {
+
+  /**
+   * Constructs a Drupal\Component\Plugin\PluginBase object.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition) {
+    $this->configuration = $configuration;
+    $this->pluginId = $plugin_id;
+    $this->pluginDefinition = $plugin_definition;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function defaultConfiguration() {
+    return [];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setConfiguration(array $configuration) {
+    $this->configuration = $configuration + $this->defaultConfiguration();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getConfiguration() {
+    return $this->configuration;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function calculateDependencies() {
+    return [];
+  }
+
+}
diff --git a/modules/payment_test/src/Plugin/PluginTest/MockManager.php b/modules/payment_test/src/Plugin/PluginTest/MockManager.php
new file mode 100644
index 0000000..ff0738f
--- /dev/null
+++ b/modules/payment_test/src/Plugin/PluginTest/MockManager.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment_test\Plugin\PluginTest\MockManager.
+ */
+
+namespace Drupal\payment_test\Plugin\PluginTest;
+
+use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Component\Plugin\PluginManagerBase;
+use Drupal\Component\Plugin\Discovery\StaticDiscovery;
+
+/**
+ * Provides a plugin manager for testing plugni-related functionality.
+ */
+class MockManager extends PluginManagerBase {
+
+  /**
+   * Constructs a new instance.
+   */
+  public function __construct() {
+    $this->discovery = new StaticDiscovery();
+
+    $this->discovery->setDefinition('payment_test_plugin', array(
+      'label' => t('Plugin'),
+      'class' => 'Drupal\payment_test\Plugin\PluginTest\MockPlugin',
+    ));
+
+    $this->discovery->setDefinition('payment_test_configurable_plugin', array(
+      'label' => t('Configurable plugin'),
+      'class' => 'Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin',
+    ));
+
+    $this->factory = new DefaultFactory($this->discovery);
+  }
+}
diff --git a/modules/payment_test/src/Plugin/PluginTest/MockPlugin.php b/modules/payment_test/src/Plugin/PluginTest/MockPlugin.php
new file mode 100644
index 0000000..eaefbbf
--- /dev/null
+++ b/modules/payment_test/src/Plugin/PluginTest/MockPlugin.php
@@ -0,0 +1,17 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment_test\Plugin\PluginTest\MockPlugin.
+ */
+
+namespace Drupal\payment_test\Plugin\PluginTest;
+
+use Drupal\Core\Plugin\PluginBase;
+
+/**
+ * Provides a mock plugin.
+ */
+class MockPlugin extends PluginBase {
+
+}
diff --git a/payment.install b/payment.install
index 9e6d0a0..07a382d 100644
--- a/payment.install
+++ b/payment.install
@@ -9,61 +9,6 @@
  * Implements hook_schema().
  */
 function payment_schema() {
-  $schema['payment_line_item'] = array(
-    'fields' => array(
-      'amount' => array(
-        'type' => 'float',
-        'size' => 'big',
-        'not null' => TRUE,
-      ),
-      'amount_total' => array(
-        'type' => 'float',
-        'size' => 'big',
-        'not null' => TRUE,
-      ),
-      'currency_code' => array(
-        'type' => 'varchar',
-        'length' => 3,
-        'not null' => TRUE,
-      ),
-      'name' => array(
-        'type' => 'varchar',
-        'length' => 255,
-      ),
-      'payment_id' => array(
-        'description' => 'The {payment}.id this line item belongs to.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'plugin_configuration' => array(
-        'type' => 'blob',
-        'not null' => TRUE,
-        'serialize' => TRUE,
-      ),
-      'plugin_id' => array(
-        'type' => 'varchar',
-        'length' => 255,
-      ),
-      'quantity' => array(
-        'type' => 'int',
-        'default' => 1,
-        'not null' => TRUE,
-      ),
-    ),
-    'primary key' => array('name', 'payment_id'),
-    'foreign keys' => array(
-      'payment_id' => array(
-        'table' => 'payment',
-        'columns' => array(
-          'payment_id' => 'id',
-        ),
-      ),
-    ),
-    'indexes' => array(
-      'payment_id' => array('payment_id'),
-    ),
-  );
   $schema['payment_queue'] = array(
     'fields' => array(
       'acquisition_code' => array(
@@ -107,40 +52,6 @@ function payment_schema() {
       'queue_id' => array('queue_id'),
     ),
   );
-  $schema['payment_status'] = array(
-    'fields' => array(
-      'created' => array(
-        'type' => 'int',
-        'not null' => TRUE,
-      ),
-      'payment_id' => array(
-        'description' => 'The payment ID.',
-        'type' => 'int',
-        'not null' => TRUE,
-        'default' => 0,
-      ),
-      'plugin_id' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-      ),
-      'id' => array(
-        'type' => 'serial',
-      ),
-    ),
-    'foreign keys' => array(
-      'payment_id' => array(
-        'table' => 'payment',
-        'columns' => array(
-          'payment_id' => 'id',
-        ),
-      ),
-    ),
-    'indexes' => array(
-      'payment_id' => array('payment_id'),
-    ),
-    'primary key' => array('id'),
-  );
 
   return $schema;
 }
diff --git a/src/DatabaseQueue.php b/src/DatabaseQueue.php
index 2d740f6..698e785 100644
--- a/src/DatabaseQueue.php
+++ b/src/DatabaseQueue.php
@@ -153,7 +153,7 @@ class DatabaseQueue implements QueueInterface {
    */
   public function claimPayment($payment_id) {
     $acquisition_code = $this->tryClaimPaymentOnce($payment_id);
-    // If a payment cannot be claimed at the first try, wait until the prevous
+    // If a payment cannot be claimed at the first try, wait until the previous
     // claim has expired and try to claim the payment one more time.
     if ($acquisition_code === FALSE) {
       sleep($this->getClaimExpirationPeriod());
@@ -232,10 +232,10 @@ class DatabaseQueue implements QueueInterface {
     }
     $query = $this->database->select('payment_queue', 'pq');
     $query->addJoin('INNER', 'payment', 'p', 'p.id = pq.payment_id');
-    $query->addJoin('INNER', 'payment_status', 'ps', 'p.last_payment_status_id = ps.id');
+    $query->addJoin('INNER', 'payment__payment_statuses', 'p_ps', 'p.id = p_ps.entity_id AND p.last_payment_status_delta = p_ps.delta');
     $query->fields('pq', array('payment_id'))
       ->condition('pq.category_id', $category_id)
-      ->condition('ps.plugin_id', $allowed_payment_status_ids)
+      ->condition('p_ps.payment_statuses_plugin_id', $allowed_payment_status_ids)
       ->condition('p.owner', $owner_id)
       ->condition('pq.queue_id', $this->queueId);
 
diff --git a/src/Element/PaymentStatusesDisplay.php b/src/Element/PaymentStatusesDisplay.php
index f6fa198..d4fa413 100644
--- a/src/Element/PaymentStatusesDisplay.php
+++ b/src/Element/PaymentStatusesDisplay.php
@@ -78,6 +78,7 @@ class PaymentStatusesDisplay extends FormElement implements ContainerFactoryPlug
     if (!isset($element['#payment']) || !($element['#payment'] instanceof PaymentInterface)) {
       throw new \InvalidArgumentException('The payment does not implement \Drupal\payment\Entity\PaymentInterface.');
     }
+    /** @var \Drupal\payment\Entity\PaymentInterface $payment */
     $payment = $element['#payment'];
     $element['table'] = array(
       '#empty' => $this->t('There are no statuses.'),
diff --git a/src/Entity/Payment.php b/src/Entity/Payment.php
index 682061f..53cb25d 100644
--- a/src/Entity/Payment.php
+++ b/src/Entity/Payment.php
@@ -7,14 +7,10 @@
 
 namespace Drupal\payment\Entity;
 
-use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\payment\Event\PaymentEvents;
-use Drupal\payment\Event\PaymentStatusSet;
-use Drupal\payment\Payment as PaymentServiceWrapper;
 use Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface;
 use Drupal\payment\Plugin\Payment\Method\PaymentMethodInterface as PluginPaymentMethodInterface;
 use Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface as PluginPaymentStatusInterface;
@@ -62,51 +58,20 @@ use Drupal\user\UserInterface;
 class Payment extends ContentEntityBase implements PaymentInterface {
 
   /**
-   * The payment method.
-   *
-   * @var \Drupal\payment\Plugin\Payment\Method\PaymentMethodInterface
-   */
-  protected $method;
-
-  /**
-   * The payment type.
-   *
-   * @var \Drupal\payment\Plugin\Payment\Type\PaymentTypeInterface
-   */
-  protected $type;
-
-  /**
-   * Line items.
-   *
-   * @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface[]
-   *   Keys are line item machine names.
-   */
-  protected $lineItems = [];
-
-  /**
-   * Payment statuses.
-   *
-   * @var array
-   *   Values are \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface
-   *   objects.
-   */
-  protected $statuses = [];
-
-  /**
    * {@inheritdoc}
    */
-  public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = []) {
-    parent::__construct($values, $entity_type, $bundle, $translations);
-    $payment_type_manager = PaymentServiceWrapper::typeManager();
-    if ($payment_type_manager instanceof CachedDiscoveryInterface) {
-      $payment_type_manager->clearCachedDefinitions();
-    }
-    // When a payment is newly created, its bundle is set, but there is no
-    // plugin yet.
-    if (!isset($values['type'])) {
-      $this->type = PaymentServiceWrapper::typeManager()->createInstance($this->bundle());
+  public function __construct(array $values, $entity_type, $bundle = FALSE, $translations = array()) {
+    // Unserialize the values for fields that are stored in the base table,
+    // because the entity storage does not do that.
+    $property_names = ['payment_method', 'payment_type'];
+    foreach ($property_names as $property_name) {
+      if (isset($values[$property_name])) {
+        foreach ($values[$property_name] as &$item_values) {
+          $item_values['plugin_configuration'] = unserialize($item_values['plugin_configuration']);
+        }
+      }
     }
-    $this->type->setPayment($this);
+    parent::__construct($values, $entity_type, $bundle, $translations);
   }
 
   /**
@@ -134,7 +99,10 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    * {@inheritdoc}
    */
   public function getPaymentType() {
-    return $this->type;
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $field_item */
+    $field_item = $this->get('payment_type')[0];
+
+    return $field_item->getContainedPluginInstance();
   }
 
   /**
@@ -164,9 +132,7 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    * {@inheritdoc}
    */
   public function setLineItems(array $line_items) {
-    /** @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface[] $line_items */
     foreach ($line_items as $line_item) {
-      $line_item->setPayment($this);
       $this->setLineItem($line_item);
     }
 
@@ -178,7 +144,12 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    */
   public function setLineItem(PaymentLineItemInterface $line_item) {
     $line_item->setPayment($this);
-    $this->lineItems[$line_item->getName()] = $line_item;
+    $line_items = $this->getLineItems();
+    $line_items[] = $line_item;
+    foreach (array_values($line_items) as $delta => $line_item) {
+      $this->get('line_items')[$delta]->setValue($line_item);
+    }
+
 
     return $this;
   }
@@ -187,7 +158,13 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    * {@inheritdoc}
    */
   public function unsetLineItem($name) {
-    unset($this->lineItems[$name]);
+    $line_items = $this->getLineItems();
+    foreach ($line_items as $delta => $line_item) {
+      if ($line_item->getName() == $name) {
+        unset($line_items[$delta]);
+      }
+    }
+    $this->get('line_items')->setValue($line_items);
 
     return $this;
   }
@@ -196,14 +173,30 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    * {@inheritdoc}
    */
   public function getLineItems() {
-    return $this->lineItems;
+    $line_items = [];
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $field_item */
+    foreach ($this->get('line_items') as $field_item) {
+      /** @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface $line_item */
+      $line_item = $field_item->getContainedPluginInstance();
+      if ($line_item) {
+        $line_items[$line_item->getName()] = $line_item;
+      }
+    }
+
+    return $line_items;
   }
 
   /**
    * {@inheritdoc}
    */
   public function getLineItem($name) {
-    return isset($this->lineItems[$name]) ? $this->lineItems[$name] : NULL;
+    $line_items = $this->getLineItems();
+    foreach ($line_items as $delta => $line_item) {
+      if ($line_item->getName() == $name) {
+        return $line_item;
+      }
+    }
+    return NULL;
   }
 
   /**
@@ -211,9 +204,9 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    */
   public function getLineItemsByType($plugin_id) {
     $line_items = [];
-    foreach ($this->getLineItems() as $line_item) {
+    foreach ($this->getLineItems() as $name => $line_item) {
       if ($line_item->getPluginId() == $plugin_id) {
-        $line_items[$line_item->getName()] = $line_item;
+        $line_items[$name] = $line_item;
       }
     }
 
@@ -225,10 +218,10 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    */
   public function setPaymentStatuses(array $statuses) {
     /** @var \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface[] $statuses */
-    foreach ($statuses as $status) {
+    foreach (array_values($statuses) as $delta => $status) {
       $status->setPayment($this);
+      $this->get('payment_statuses')[$delta]->setValue($status, FALSE);
     }
-    $this->statuses = array_values($statuses);
 
     return $this;
   }
@@ -236,18 +229,20 @@ class Payment extends ContentEntityBase implements PaymentInterface {
   /**
    * {@inheritdoc}
    */
-  public function setPaymentStatus(PluginPaymentStatusInterface $status, $notify = TRUE) {
+  public function setPaymentStatus(PluginPaymentStatusInterface $status) {
     $previous_status = $this->getPaymentStatus();
     $status->setPayment($this);
     // Prevent duplicate statuses.
     if (!$this->getPaymentStatus() || $this->getPaymentStatus()->getPluginId() != $status->getPluginId()) {
-      $this->statuses[] = $status;
-    }
-    if ($notify) {
-      /** @var \Drupal\payment\EventDispatcherInterface $event_dispatcher */
-      $event_dispatcher = \Drupal::service('payment.event_dispatcher');
-      $event_dispatcher->setPaymentStatus($this, $previous_status);
+      $payment_statuses = $this->getPaymentStatuses();
+      $payment_statuses[] = $status;
+      foreach (array_values($payment_statuses) as $delta => $payment_status) {
+        $this->get('payment_statuses')[$delta]->setValue($payment_status);
+      }
     }
+    /** @var \Drupal\payment\EventDispatcherInterface $event_dispatcher */
+    $event_dispatcher = \Drupal::service('payment.event_dispatcher');
+    $event_dispatcher->setPaymentStatus($this, $previous_status);
 
     return $this;
   }
@@ -256,14 +251,27 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    * {@inheritdoc}
    */
   public function getPaymentStatuses() {
-    return $this->statuses;
+    $payment_statuses = [];
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $field_item */
+    foreach ($this->get('payment_statuses') as $field_item) {
+      $payment_statuses[] = $field_item->getContainedPluginInstance();
+    }
+
+    return array_filter($payment_statuses);
   }
 
   /**
    * {@inheritdoc}
    */
   public function getPaymentStatus() {
-    return $this->statuses ? end($this->statuses) : NULL;
+    $deltas = [];
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $field_item */
+    foreach ($this->get('payment_statuses') as $delta => $field_item) {
+      $deltas[] = $delta;
+    }
+    $field_item = $this->get('payment_statuses')[max($deltas)];
+
+    return $field_item->getContainedPluginInstance();
   }
 
   /**
@@ -271,7 +279,9 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    */
   public function setPaymentMethod(PluginPaymentMethodInterface $payment_method) {
     $payment_method->setPayment($this);
-    $this->method = $payment_method;
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $field_item */
+    $field_item = $this->get('payment_method')[0];
+    $field_item->setContainedPluginInstance($payment_method);
 
     return $this;
   }
@@ -280,7 +290,10 @@ class Payment extends ContentEntityBase implements PaymentInterface {
    * {@inheritdoc}
    */
   public function getPaymentMethod() {
-    return $this->method;
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $field_item */
+    $field_item = $this->get('payment_method')[0];
+
+    return $field_item->getContainedPluginInstance();
   }
 
   /**
@@ -350,39 +363,6 @@ class Payment extends ContentEntityBase implements PaymentInterface {
   /**
    * {@inheritdoc}
    */
-  public static function postLoad(EntityStorageInterface $storage, array &$entities) {
-    /** @var \Drupal\payment\Entity\PaymentInterface[] $entities */
-    foreach ($entities as $payment) {
-      if ($payment->getPaymentMethod()) {
-        $payment->getPaymentMethod()->setPayment($payment);
-      }
-    }
-    /** @var \Drupal\payment\Entity\Payment\PaymentStorageInterface $storage */
-    $storage->loadLineItems($entities);
-    $storage->loadPaymentStatuses($entities);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
-    /** @var \Drupal\payment\Entity\Payment\PaymentStorageInterface $storage */
-    $storage->saveLineItems($this->getLineItems());
-    $storage->savePaymentStatuses($this->getPaymentStatuses());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function postDelete(EntityStorageInterface $storage, array $entities) {
-    /** @var \Drupal\payment\Entity\Payment\PaymentStorageInterface $storage */
-    $storage->deleteLineItems(array_keys($entities));
-    $storage->deletePaymentStatuses(array_keys($entities));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
     $fields['bundle'] = BaseFieldDefinition::create('string')
       ->setLabel(t('Payment type'))
@@ -408,6 +388,16 @@ class Payment extends ContentEntityBase implements PaymentInterface {
       ->setSettings(array(
         'target_type' => 'user',
       ));
+    $fields['line_items'] = BaseFieldDefinition::create('payment_line_item')
+      ->setLabel(t('Line items'))
+      ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED);
+    $fields['payment_method'] = BaseFieldDefinition::create('payment_method')
+      ->setLabel(t('Payment method'));
+    $fields['payment_statuses'] = BaseFieldDefinition::create('payment_status')
+      ->setLabel(t('Payment statuses'))
+      ->setCardinality(BaseFieldDefinition::CARDINALITY_UNLIMITED);
+    $fields['payment_type'] = BaseFieldDefinition::create('payment_type')
+      ->setLabel(t('Payment type'));
     $fields['uuid'] = BaseFieldDefinition::create('uuid')
       ->setLabel(t('Universally Unique ID'))
       ->setReadOnly(TRUE);
@@ -415,33 +405,4 @@ class Payment extends ContentEntityBase implements PaymentInterface {
     return $fields;
   }
 
-  /**
-   * Clones the instance.
-   */
-  public function __clone() {
-    parent::__clone();
-    // Clone the payment type.
-    $this->type = clone $this->type;
-    $this->type->setPayment($this);
-
-    // Clone the payment method.
-    if ($this->getPaymentMethod()) {
-      $this->setPaymentMethod(clone $this->getPaymentMethod());
-    }
-
-    // Clone the line items.
-    $cloned_line_items = [];
-    foreach ($this->getLineItems() as $line_item) {
-      $cloned_line_items[] = clone $line_item;
-    }
-    $this->setLineItems($cloned_line_items);
-
-    // Clone the payment statuses.
-    $cloned_statuses = [];
-    foreach ($this->getPaymentStatuses() as $status) {
-      $cloned_statuses[] = clone $status;
-    }
-    $this->setPaymentStatuses($cloned_statuses);
-  }
-
 }
diff --git a/src/Entity/Payment/PaymentListBuilder.php b/src/Entity/Payment/PaymentListBuilder.php
index 8a9def5..1556dc4 100644
--- a/src/Entity/Payment/PaymentListBuilder.php
+++ b/src/Entity/Payment/PaymentListBuilder.php
@@ -89,7 +89,8 @@ class PaymentListBuilder extends EntityListBuilder {
    * {@inheritdoc}
    */
   public function load() {
-    // @todo Add (table)sorting.
+    // @todo Add (table)sorting once https://drupal.org/node/2134761 has been
+    //   fixed.
     $page = pager_find_page();
     $start = static::PAYMENTS_PER_PAGE * ($page);
     $query = $this->storage->getQuery();
diff --git a/src/Entity/Payment/PaymentStorage.php b/src/Entity/Payment/PaymentStorage.php
index 469c638..cd97eed 100644
--- a/src/Entity/Payment/PaymentStorage.php
+++ b/src/Entity/Payment/PaymentStorage.php
@@ -14,8 +14,6 @@ use Drupal\Core\Entity\EntityManagerInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\Core\Language\LanguageManagerInterface;
-use Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface;
-use Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface;
 use Drupal\payment\Plugin\Payment\Status\PaymentStatusManagerInterface;
 use Drupal\payment\Plugin\Payment\Type\PaymentTypeManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -23,21 +21,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 /**
  * Handles storage for payment entities.
  */
-class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageInterface {
-
-  /**
-   * The payment line item manager.
-   *
-   * @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface
-   */
-  protected $paymentLineItemManager;
-
-  /**
-   * The payment method manager.
-   *
-   * @var \Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface
-   */
-  protected $paymentMethodManager;
+class PaymentStorage extends SqlContentEntityStorage {
 
   /**
    * The payment status manager.
@@ -66,19 +50,13 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn
    *   The entity cache.
    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
    *   The language manager.
-   * @param \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface $payment_line_item_manager
-   *   The payment line item manager.
-   * @param \Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface $payment_method_manager
-   *   The payment method manager.
    * @param \Drupal\payment\Plugin\Payment\Status\PaymentStatusManagerInterface $payment_status_manager
    *   The payment status manager.
    * @param \Drupal\payment\Plugin\Payment\Type\PaymentTypeManagerInterface $payment_type_manager
    *   The payment type manager.
    */
-  public function __construct(EntityTypeInterface $entity_type, Connection $database, EntityManagerInterface $entity_manager, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, PaymentLineItemManagerInterface $payment_line_item_manager, PaymentMethodManagerInterface $payment_method_manager, PaymentStatusManagerInterface $payment_status_manager, PaymentTypeManagerInterface $payment_type_manager) {
+  public function __construct(EntityTypeInterface $entity_type, Connection $database, EntityManagerInterface $entity_manager, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, PaymentStatusManagerInterface $payment_status_manager, PaymentTypeManagerInterface $payment_type_manager) {
     parent::__construct($entity_type, $database, $entity_manager, $cache, $language_manager);
-    $this->paymentLineItemManager = $payment_line_item_manager;
-    $this->paymentMethodManager = $payment_method_manager;
     $this->paymentStatusManager = $payment_status_manager;
     $this->paymentTypeManager = $payment_type_manager;
   }
@@ -87,7 +65,7 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn
    * {@inheritdoc}
    */
   public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
-    return new static($entity_type, $container->get('database'), $container->get('entity.manager'), $container->get('cache.entity'), $container->get('language_manager'), $container->get('plugin.manager.payment.line_item'), $container->get('plugin.manager.payment.method'), $container->get('plugin.manager.payment.status'), $container->get('plugin.manager.payment.type'));
+    return new static($entity_type, $container->get('database'), $container->get('entity.manager'), $container->get('cache.entity'), $container->get('language_manager'), $container->get('plugin.manager.payment.status'), $container->get('plugin.manager.payment.type'));
   }
 
   /**
@@ -96,6 +74,9 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn
   public function create(array $values = []) {
     /** @var \Drupal\payment\Entity\PaymentInterface $payment */
     $payment = parent::create($values);
+    $payment_type = $this->paymentTypeManager->createInstance($values['bundle']);
+    $payment_type->setPayment($payment);
+    $payment->get('payment_type')->setValue($payment_type);
     $status = $this->paymentStatusManager->createInstance('payment_created')
       ->setCreated(time());
     $payment->setPaymentStatus($status);
@@ -107,6 +88,7 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn
    * {@inheritdoc}
    */
   protected function buildQuery($ids, $revision_id = FALSE) {
+    // @todo  What does this code do?
     $query = $this->database->select('payment', 'payment');
     $query->addTag('payment_load_multiple');
     $query->fields('payment');
@@ -120,163 +102,19 @@ class PaymentStorage extends SqlContentEntityStorage implements PaymentStorageIn
   /**
    * {@inheritdoc}
    */
-  function mapFromStorageRecords(array $records) {
-    foreach ($records as $id => $record) {
-      $payment_method = $record->payment_method_id ? $this->paymentMethodManager->createInstance($record->payment_method_id, unserialize($record->payment_method_configuration)) : NULL;
-      $payment_type = $this->paymentTypeManager->createInstance($record->payment_type_id, unserialize($record->payment_type_configuration));
-      $records[$id] = (object) array(
-        'changed' => $record->changed,
-        'created' => $record->created,
-        'currency' => $record->currency,
-        'id' => (int) $record->id,
-        'owner' => (int) $record->owner,
-        'method' => $payment_method,
-        'type' => $payment_type,
-        'bundle' => $payment_type->getPluginId(),
-        'uuid' => $record->uuid,
-      );
-    }
-
-    return parent::mapFromStorageRecords($records);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   protected function mapToStorageRecord(ContentEntityInterface $entity, $table_name = NULL) {
     /** @var \Drupal\payment\Entity\PaymentInterface $payment */
     $payment = $entity;
 
-    $record = new \stdClass();
-    $record->bundle = $payment->bundle();
-    $record->changed= $payment->getChangedTime();
-    $record->created = $payment->getCreatedTime();
-    $record->currency = $payment->getCurrencyCode();
-    $record->id = $payment->id();
-    $record->first_payment_status_id = current($payment->getPaymentStatuses())->getId();
-    $record->last_payment_status_id = $payment->getPaymentStatus()->getId();
-    $record->owner = $payment->getOwnerId();
-    $record->payment_method_configuration = serialize($payment->getPaymentMethod() ? $payment->getPaymentMethod()->getConfiguration() : []);
-    $record->payment_method_id = $payment->getPaymentMethod() ? $payment->getPaymentMethod()->getPluginId() : NULL;
-    $record->payment_type_configuration = serialize($payment->getPaymentType()->getConfiguration());
-    $record->payment_type_id = $payment->getPaymentType()->getPluginId();
-    $record->uuid = $payment->uuid();
-
-    return $record;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function loadLineItems(array $entities) {
-    /** @var \Drupal\payment\Entity\PaymentInterface[] $entities */
-    $result = $this->database->select('payment_line_item', 'pli')
-      ->fields('pli', array('payment_id', 'plugin_configuration', 'plugin_id'))
-      ->condition('payment_id', array_keys($entities))
-      ->execute();
-    while ($line_item_data = $result->fetchAssoc()) {
-      /** @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface $line_item */
-      $line_item = $this->paymentLineItemManager->createInstance($line_item_data['plugin_id'], unserialize($line_item_data['plugin_configuration']));
-      $line_item->setPayment($entities[$line_item_data['payment_id']]);
-      $entities[$line_item_data['payment_id']]->setLineItem($line_item);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function saveLineItems(array $line_items) {
-    /** @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface[] $line_items */
-    if ($line_items) {
-      $this->deleteLineItems(array(reset($line_items)->getPayment()->id()));
-      $query = $this->database->insert('payment_line_item')
-        ->fields(array('amount', 'amount_total', 'currency_code', 'name', 'payment_id', 'plugin_configuration', 'plugin_id', 'quantity'));
-      foreach ($line_items as $line_item) {
-        $query->values(array(
-          'amount' => $line_item->getAmount(),
-          'amount_total' => $line_item->getTotalAmount(),
-          'currency_code' => $line_item->getCurrencyCode(),
-          'name' => $line_item->getName(),
-          'payment_id' => $line_item->getPayment()->id(),
-          'plugin_configuration' => serialize($line_item->getConfiguration()),
-          'plugin_id' => $line_item->getPluginId(),
-          'quantity' => $line_item->getQuantity(),
-        ));
-      }
-      $query->execute();
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deleteLineItems(array $ids) {
-    $this->database->delete('payment_line_item')
-      ->condition('payment_id', $ids)
-      ->execute();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function loadPaymentStatuses(array $entities) {
-    /** @var \Drupal\payment\Entity\PaymentInterface[] $entities */
-    $result = $this->database->select('payment_status', 'ps')
-      ->fields('ps')
-      ->condition('payment_id', array_keys($entities))
-      ->orderBy('id', 'ASC')
-      ->execute();
-    $statuses= array_fill_keys(array_keys($entities), []);
-    while ($status_data = $result->fetchAssoc()) {
-      $status = $this->paymentStatusManager->createInstance($status_data['plugin_id']);
-      $status->setCreated((int) $status_data['created']);
-      $status->setId((int) $status_data['id']);
-      $status->setPayment($entities[$status_data['payment_id']]);
-
-      $statuses[$status->getPayment()->id()][] = $status;
-    }
-    foreach ($entities as $payment) {
-      $payment->setPaymentStatuses($statuses[$payment->id()]);
+    $record = parent::mapToStorageRecord($entity, $table_name);
+    $deltas = [];
+    foreach ($payment->getPaymentStatuses() as $delta => $item) {
+      $deltas[] = $delta;
     }
-  }
+    $record->first_payment_status_delta = min($deltas);
+    $record->last_payment_status_delta = max($deltas);
 
-  /**
-   * {@inheritdoc}
-   */
-  public function savePaymentStatuses(array $statuses) {
-    /** @var \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface[] $statuses */
-    if ($statuses) {
-      foreach ($statuses as $status) {
-        // Statuses cannot be edited, so only save the ones without an ID.
-        if (!$status->getId()) {
-          $record = array(
-            'created' => $status->getCreated(),
-            'payment_id' => $status->getPayment()->id(),
-            'plugin_id' => $status->getPluginId(),
-          );
-          $id = $this->database->insert('payment_status')
-            ->fields($record)
-            ->execute();
-          $status->setId($id);
-        }
-      }
-      $this->database->update('payment')
-        ->condition('id', reset($statuses)->getPayment()->id())
-        ->fields(array(
-          'first_payment_status_id' => reset($statuses)->getId(),
-          'last_payment_status_id' => end($statuses)->getId(),
-        ))
-        ->execute();
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deletePaymentStatuses(array $ids) {
-    $this->database->delete('payment_status')
-      ->condition('payment_id', $ids)
-      ->execute();
+    return $record;
   }
 
 }
diff --git a/src/Entity/Payment/PaymentStorageInterface.php b/src/Entity/Payment/PaymentStorageInterface.php
deleted file mode 100644
index 3655ba6..0000000
--- a/src/Entity/Payment/PaymentStorageInterface.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\payment\Entity\Payment\PaymentStorageInterface.
- */
-
-namespace Drupal\payment\Entity\Payment;
-
-use Drupal\Core\Entity\EntityStorageInterface;
-
-/**
- * A storage controller for payment entities.
- */
-interface PaymentStorageInterface extends EntityStorageInterface {
-
-  /**
-   * Loads payment line items.
-   *
-   * @param int[] $ids
-   *   Payment IDs.
-   *
-   * @return array[]
-   *   Keys are payment IDs, values are arrays of which keys are line item names
-   *   and values are \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface
-   *   objects.
-   */
-  public function loadLineItems(array $ids);
-
-  /**
-   * Saves payment line items.
-   *
-   * @param \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface[] $line_items
-   */
-  public function saveLineItems(array $line_items);
-
-  /**
-   * Deletes payment line items.
-   *
-   * @param string[] $ids
-   *   Keys are payment IDs. Values are line item names.
-   */
-  public function deleteLineItems(array $ids);
-
-  /**
-   * Loads payment statuses.
-   *
-   * @param int[] $ids
-   *   Payment IDs.
-   *
-   * @return array[]
-   *   Keys are payment IDs, values are arrays of
-   *   \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface objects.
-   */
-  public function loadPaymentStatuses(array $ids);
-
-  /**
-   * Saves payment statuses.
-   *
-   * @param \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface[] $statuses
-   */
-  public function savePaymentStatuses(array $statuses);
-
-  /**
-   * Deletes payment statuses.
-   *
-   * @param int[] $ids
-   *   Payment IDs.
-   */
-  public function deletePaymentStatuses(array $ids);
-}
diff --git a/src/Entity/Payment/PaymentStorageSchema.php b/src/Entity/Payment/PaymentStorageSchema.php
index b0b2971..88d8cf5 100644
--- a/src/Entity/Payment/PaymentStorageSchema.php
+++ b/src/Entity/Payment/PaymentStorageSchema.php
@@ -26,54 +26,39 @@ class PaymentStorageSchema extends SqlContentEntityStorageSchema {
   }
 
   /**
+   * Adds non-field columns to the schema.
    *
+   * @param array[] $schema
+   *   The existing schema.
    */
   protected function alterEntitySchemaWithNonFieldColumns(array &$schema) {
     $schema['payment']['fields'] += array(
-      'first_payment_status_id' => array(
-        'description' => "The {payment_status_item}.id of this payment's first status item.",
+      'first_payment_status_delta' => array(
+        'description' => "The {payment__payment_statuses}.delta of this payment's first status item.",
         'type' => 'int',
         'unsigned' => TRUE,
         'default' => 0,
         'not null' => TRUE,
       ),
-      'last_payment_status_id' => array(
-        'description' => "The {payment_status_item}.id of this payment's most recent status item.",
+      'last_payment_status_delta' => array(
+        'description' => "The {payment__payment_statuses}.delta of this payment's most recent status item.",
         'type' => 'int',
         'unsigned' => TRUE,
         'default' => 0,
         'not null' => TRUE,
       ),
-      'payment_method_configuration' => array(
-        'type' => 'blob',
-        'not null' => TRUE,
-        'serialize' => TRUE,
-      ),
-      'payment_method_id' => array(
-        'type' => 'varchar',
-        'length' => 255,
-      ),
-      'payment_type_configuration' => array(
-        'type' => 'blob',
-        'not null' => TRUE,
-        'serialize' => TRUE,
-      ),
-      'payment_type_id' => array(
-        'type' => 'varchar',
-        'length' => 255,
-      ),
     );
     $schema['payment']['foreign keys'] += array(
-      'first_payment_status_id' => array(
-        'table' => 'payment_status_item',
+      'first_payment_status_delta' => array(
+        'table' => 'payment__payment_statuses',
         'columns' => array(
-          'first_payment_status_id' => 'id',
+          'first_payment_status_delta' => 'delta',
         ),
       ),
-      'last_payment_status_id' => array(
-        'table' => 'payment_status_item',
+      'last_payment_status_delta' => array(
+        'table' => 'payment__payment_statuses',
         'columns' => array(
-          'last_payment_status_id' => 'id',
+          'last_payment_status_delta' => 'delta',
         ),
       ),
       'owner' => array(
@@ -83,8 +68,6 @@ class PaymentStorageSchema extends SqlContentEntityStorageSchema {
         ),
       ),
     );
-
-    return $schema;
   }
 
 }
diff --git a/src/Entity/PaymentInterface.php b/src/Entity/PaymentInterface.php
index 8fb1f61..e3dea58 100644
--- a/src/Entity/PaymentInterface.php
+++ b/src/Entity/PaymentInterface.php
@@ -121,8 +121,7 @@ interface PaymentInterface extends ContentEntityInterface, EntityChangedInterfac
   /**
    * Sets/replaces all statuses without notifications.
    *
-   * @param array $statuses
-   *   \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface objects.
+   * @param \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface[] $statuses
    *
    * @return \Drupal\payment\Entity\PaymentInterface
    */
@@ -132,12 +131,10 @@ interface PaymentInterface extends ContentEntityInterface, EntityChangedInterfac
    * Sets a status.
    *
    * @param \Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface $status
-   * @param bool $notify
-   *   Whether or not to trigger a notification event.
    *
    * @return \Drupal\payment\Entity\PaymentInterface
    */
-  public function setPaymentStatus(PluginPaymentStatusInterface $status, $notify = TRUE);
+  public function setPaymentStatus(PluginPaymentStatusInterface $status);
 
   /**
    * Gets all payment statuses.
diff --git a/src/PaymentAwareInterface.php b/src/PaymentAwareInterface.php
new file mode 100644
index 0000000..8cf0b9e
--- /dev/null
+++ b/src/PaymentAwareInterface.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * Contains \Drupal\payment\PaymentAwareInterface.
+ */
+
+namespace Drupal\payment;
+
+use Drupal\payment\Entity\PaymentInterface;
+
+/**
+ * Defines an object that can be aware of a payment entity.
+ */
+interface PaymentAwareInterface {
+
+  /**
+   * Sets the payment.
+   *
+   * @param \Drupal\payment\Entity\PaymentInterface $payment
+   *
+   * @return $this
+   */
+  public function setPayment(PaymentInterface $payment);
+
+  /**
+   * Gets the payment.
+   *
+   * @return \Drupal\payment\Entity\PaymentInterface
+   */
+  public function getPayment();
+
+}
diff --git a/src/PaymentAwareTrait.php b/src/PaymentAwareTrait.php
new file mode 100644
index 0000000..1f9de56
--- /dev/null
+++ b/src/PaymentAwareTrait.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * Contains \Drupal\payment\PaymentAwareTrait.
+ */
+
+namespace Drupal\payment;
+
+use Drupal\payment\Entity\PaymentInterface;
+
+/**
+ * Provides a default implementation of \Drupal\payment\PaymentAwareInterface.
+ */
+trait PaymentAwareTrait {
+
+  /**
+   * The payment.
+   *
+   * @var \Drupal\payment\Entity\PaymentInterface
+   */
+  protected $payment;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPayment() {
+    return $this->payment;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setPayment(PaymentInterface $payment) {
+    $this->payment = $payment;
+
+    return $this;
+  }
+
+}
diff --git a/src/Plugin/DataType/PluginConfiguration.php b/src/Plugin/DataType/PluginConfiguration.php
new file mode 100644
index 0000000..a919869
--- /dev/null
+++ b/src/Plugin/DataType/PluginConfiguration.php
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment\Plugin\DataType\PluginConfiguration.
+ */
+
+namespace Drupal\payment\Plugin\DataType;
+
+use Drupal\Component\Plugin\ConfigurablePluginInterface;
+use Drupal\Core\TypedData\TypedData;
+use Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface;
+
+/**
+ * Provides a plugin configuration data type.
+ *
+ * @DataType(
+ *   id = "payment_plugin_configuration",
+ *   label = @Translation("Plugin configuration")
+ * )
+ */
+class PluginConfiguration extends TypedData {
+
+  /**
+   * The plugin configuration.
+   *
+   * @var mixed[]
+   */
+  protected $value;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($value, $notify = TRUE) {
+    $value = (array) $value;
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $parent */
+    $parent = $this->getParent();
+    $plugin_instance = $parent->getContainedPluginInstance();
+    if ($plugin_instance instanceof ConfigurablePluginInterface) {
+      $plugin_instance->setConfiguration($value);
+      $this->parent->onChange($this->getName());
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $parent */
+    $parent = $this->getParent();
+    $plugin_instance = $parent->getContainedPluginInstance();
+    if ($plugin_instance instanceof ConfigurablePluginInterface) {
+      return $plugin_instance->getConfiguration();
+    }
+    return [];
+  }
+
+}
diff --git a/src/Plugin/DataType/PluginId.php b/src/Plugin/DataType/PluginId.php
new file mode 100644
index 0000000..f0e6fb4
--- /dev/null
+++ b/src/Plugin/DataType/PluginId.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment\Plugin\DataType\PluginId.
+ */
+
+namespace Drupal\payment\Plugin\DataType;
+
+use Drupal\Core\TypedData\Plugin\DataType\String;
+
+/**
+ * Provides a plugin ID data type.
+ *
+ * @DataType(
+ *   id = "payment_plugin_id",
+ *   label = @Translation("Plugin ID")
+ * )
+ */
+class PluginId extends String {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($value, $notify = TRUE) {
+    $value = (string) $value;
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $parent */
+    $parent = $this->getParent();
+    $plugin_instance = $parent->getContainedPluginInstance();
+    if ($value && (!$plugin_instance || $plugin_instance->getPluginId() != $value)) {
+      $plugin_instance = $parent->createContainedPluginInstance($value);
+      $parent->setContainedPluginInstance($plugin_instance);
+      $this->parent->onChange($this->getName());
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue() {
+    /** @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemInterface $parent */
+    $parent = $this->getParent();
+    $plugin_instance = $parent->getContainedPluginInstance();
+    if ($plugin_instance) {
+      return $plugin_instance->getPluginId();
+    }
+    return '';
+  }
+
+}
diff --git a/src/Plugin/DataType/PluginInstance.php b/src/Plugin/DataType/PluginInstance.php
new file mode 100644
index 0000000..ad48381
--- /dev/null
+++ b/src/Plugin/DataType/PluginInstance.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment\Plugin\DataType\PluginInstance.
+ */
+
+namespace Drupal\payment\Plugin\DataType;
+
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\TypedData\TypedData;
+use Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface;
+
+/**
+ * Provides a plugin instance data type.
+ *
+ * @DataType(
+ *   id = "payment_plugin_instance",
+ *   label = @Translation("Plugin instance")
+ * )
+ */
+class PluginInstance extends TypedData {
+
+  /**
+   * The plugin instance.
+   *
+   * @var \Drupal\Component\Plugin\PluginInspectionInterface
+   */
+  protected $value;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($value, $notify = TRUE) {
+    if (!$value instanceof PluginInspectionInterface) {
+      $value = NULL;
+    }
+    parent::setValue($value, $notify);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __clone() {
+    if ($this->getValue()) {
+      $this->setValue(clone $this->value);
+    }
+  }
+
+}
diff --git a/src/Plugin/Field/FieldType/LineItemItem.php b/src/Plugin/Field/FieldType/LineItemItem.php
new file mode 100644
index 0000000..585cf90
--- /dev/null
+++ b/src/Plugin/Field/FieldType/LineItemItem.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment\Plugin\Field\FieldType\LineItemItem.
+ */
+
+namespace Drupal\payment\Plugin\Field\FieldType;
+
+use Drupal\payment\Payment;
+
+/**
+ * Provides a plugin bag for payment line item plugins.
+ *
+ * @FieldType(
+ *   id = "payment_line_item",
+ *   label = @Translation("Payment line item plugins")
+ * )
+ */
+class LineItemItem extends PaymentAwarePluginBagItemBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPluginManager() {
+    // @todo Unit-test this.
+    return Payment::lineItemManager();
+  }
+
+}
diff --git a/src/Plugin/Field/FieldType/PaymentAwarePluginBagItemBase.php b/src/Plugin/Field/FieldType/PaymentAwarePluginBagItemBase.php
new file mode 100644
index 0000000..abf1019
--- /dev/null
+++ b/src/Plugin/Field/FieldType/PaymentAwarePluginBagItemBase.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment\Plugin\Field\FieldType\PaymentAwarePluginBagItemBase.
+ */
+
+namespace Drupal\payment\Plugin\Field\FieldType;
+
+use Drupal\payment\Entity\PaymentInterface;
+use Drupal\payment\PaymentAwareInterface;
+
+/**
+ * Provides a plugin bag for payment-aware plugins.
+ */
+abstract class PaymentAwarePluginBagItemBase extends PluginBagItemBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function onChange($property_name, $notify = TRUE) {
+    if ($property_name == 'plugin_configuration') {
+      $plugin_instance = $this->getContainedPluginInstance();
+      if ($plugin_instance instanceof PaymentAwareInterface) {
+        $data = $this;
+        while ($data = $data->getParent()) {
+          if ($data instanceof PaymentInterface) {
+            $plugin_instance->setPayment($data);
+            break;
+          }
+        }
+      }
+    }
+    parent::onChange($property_name, $notify);
+  }
+
+}
diff --git a/src/Plugin/Field/FieldType/PaymentMethodItem.php b/src/Plugin/Field/FieldType/PaymentMethodItem.php
new file mode 100644
index 0000000..4b0074d
--- /dev/null
+++ b/src/Plugin/Field/FieldType/PaymentMethodItem.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment\Plugin\Field\FieldType\PaymentMethodItem.
+ */
+
+namespace Drupal\payment\Plugin\Field\FieldType;
+
+use Drupal\payment\Payment;
+
+/**
+ * Provides a plugin bag for payment method plugins.
+ *
+ * @FieldType(
+ *   id = "payment_method",
+ *   label = @Translation("Payment method plugins")
+ * )
+ */
+class PaymentMethodItem extends PaymentAwarePluginBagItemBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPluginManager() {
+    // @todo Unit-test this.
+    return Payment::methodManager();
+  }
+
+}
diff --git a/src/Plugin/Field/FieldType/PaymentStatusItem.php b/src/Plugin/Field/FieldType/PaymentStatusItem.php
new file mode 100644
index 0000000..8bde494
--- /dev/null
+++ b/src/Plugin/Field/FieldType/PaymentStatusItem.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment\Plugin\Field\FieldType\PaymentStatusItem.
+ */
+
+namespace Drupal\payment\Plugin\Field\FieldType;
+
+use Drupal\payment\Payment;
+
+/**
+ * Provides a plugin bag for payment type plugins.
+ *
+ * @FieldType(
+ *   id = "payment_status",
+ *   label = @Translation("Payment status plugins")
+ * )
+ */
+class PaymentStatusItem extends PaymentAwarePluginBagItemBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPluginManager() {
+    // @todo Unit-test this.
+    return Payment::statusManager();
+  }
+
+}
diff --git a/src/Plugin/Field/FieldType/PaymentTypeItem.php b/src/Plugin/Field/FieldType/PaymentTypeItem.php
new file mode 100644
index 0000000..bf7e53f
--- /dev/null
+++ b/src/Plugin/Field/FieldType/PaymentTypeItem.php
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\payment\Plugin\Field\FieldType\PaymentTypeItem.
+ */
+
+namespace Drupal\payment\Plugin\Field\FieldType;
+
+use Drupal\payment\Payment;
+
+/**
+ * Provides a plugin bag for payment type plugins.
+ *
+ * @FieldType(
+ *   id = "payment_type",
+ *   label = @Translation("Payment type plugins")
+ * )
+ */
+class PaymentTypeItem extends PaymentAwarePluginBagItemBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPluginManager() {
+    // @todo Unit-test this.
+    return Payment::typeManager();
+  }
+
+}
diff --git a/src/Plugin/Field/FieldType/PluginBagItemBase.php b/src/Plugin/Field/FieldType/PluginBagItemBase.php
new file mode 100644
index 0000000..28e140d
--- /dev/null
+++ b/src/Plugin/Field/FieldType/PluginBagItemBase.php
@@ -0,0 +1,184 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Field\Plugin\Field\FieldType\PluginBagItemBase.
+ */
+
+namespace Drupal\payment\Plugin\Field\FieldType;
+
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Field\FieldStorageDefinitionInterface;
+use Drupal\Core\Field\FieldItemBase;
+use Drupal\Core\TypedData\DataDefinition;
+use Drupal\Core\TypedData\MapDataDefinition;
+
+/**
+ * Provides a base for plugin bag field items.
+ */
+abstract class
+PluginBagItemBase extends FieldItemBase implements PluginBagItemInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __get($name) {
+    // @todo Remove this override once https://www.drupal.org/node/2413471 has
+    //   been fixed.
+    // There is either a property object or a plain value - possibly for a
+    // not-defined property. If we have a plain value, directly return it.
+    if ($this->definition->getPropertyDefinition($name)) {
+      return $this->get($name)->getValue();
+    }
+    elseif (isset($this->values[$name])) {
+      return $this->values[$name];
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validatePluginInstance(PluginInspectionInterface $plugin_instance) {
+    if (!$this->getPluginManager()->hasDefinition($plugin_instance->getPluginId())) {
+      throw new \Exception(sprintf('Plugin manager %s does not have a definition for plugin %s.', get_class($this->getPluginManager()), $plugin_instance->getPluginId()));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function createContainedPluginInstance($plugin_id, array $plugin_configuration = []) {
+    $plugin_instance = $this->getPluginManager()
+      ->createInstance($plugin_id, $plugin_configuration);
+    $this->validatePluginInstance($plugin_instance);
+
+    return $plugin_instance;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContainedPluginInstance() {
+    return $this->get('plugin_instance')->getValue();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setContainedPluginInstance(PluginInspectionInterface $plugin_instance) {
+    $this->get('plugin_instance')->setValue($plugin_instance);
+
+    return $this;
+  }
+
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContainedPluginId() {
+    return $this->get('plugin_id')->getValue();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setContainedPluginId($plugin_id) {
+    $this->get('plugin_id')->setValue($plugin_id);
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContainedPluginConfiguration() {
+    return $this->get('plugin_configuration')->getValue();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setContainedPluginConfiguration(array $configuration) {
+    $this->get('plugin_configuration')->setValue($configuration);
+
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
+    $properties['plugin_id'] = DataDefinition::create('payment_plugin_id')
+      ->setLabel(t('Plugin ID'));
+    $properties['plugin_configuration'] = MapDataDefinition::create('payment_plugin_configuration')
+      ->setLabel(t('Plugin configuration'));
+    $properties['plugin_instance'] = MapDataDefinition::create('payment_plugin_instance')
+      ->setLabel(t('Plugin instance'));
+
+    return $properties;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function mainPropertyName() {
+    return 'plugin_instance';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function schema(FieldStorageDefinitionInterface $field_definition) {
+    $columns = array(
+      'plugin_id' => array(
+        'description' => 'The plugin ID.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'plugin_configuration' => array(
+        'description' => 'The plugin configuration.',
+        'type' => 'blob',
+        'not null' => TRUE,
+        'serialize' => TRUE,
+      ),
+    );
+
+    $schema = array(
+      'columns' => $columns,
+    );
+
+    return $schema;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isEmpty() {
+    return !$this->getContainedPluginInstance();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setValue($values, $notify = TRUE) {
+    if ($values instanceof PluginInspectionInterface) {
+      $this->setContainedPluginInstance($values);
+    }
+    elseif (is_array($values)) {
+      if (isset($values['plugin_id'])) {
+        $this->setContainedPluginId($values['plugin_id']);
+      }
+      if (isset($values['plugin_configuration'])) {
+        $this->setContainedPluginConfiguration($values['plugin_configuration']);
+      }
+    }
+    // Field API has this weird habit of setting NULL instead of calling
+    // applyDefaultValue(), so we can't throw an exception on that.
+    elseif (!is_null($values)) {
+      $type = is_object($values) ? get_class($values) : gettype($values);
+      throw new \InvalidArgumentException(sprintf('The value must implement \Drupal\Component\Plugin\PluginInspectionInterface or be an associative array, but %s was given', $type));
+    }
+  }
+
+}
diff --git a/src/Plugin/Field/FieldType/PluginBagItemInterface.php b/src/Plugin/Field/FieldType/PluginBagItemInterface.php
new file mode 100644
index 0000000..a2fff2d
--- /dev/null
+++ b/src/Plugin/Field/FieldType/PluginBagItemInterface.php
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Field\Plugin\Field\FieldType\PluginBagItemInterface.
+ */
+
+namespace Drupal\payment\Plugin\Field\FieldType;
+
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Field\FieldItemInterface;
+
+/**
+ * Defines a plugin bag field item.
+ */
+interface PluginBagItemInterface extends FieldItemInterface {
+
+  /**
+   * Returns the manager for plugins of the type contained by this item.
+   *
+   * @return \Drupal\Component\Plugin\PluginManagerInterface
+   */
+  public function getPluginManager();
+
+  /**
+   * Validates a plugin instance.
+   *
+   * @param \Drupal\Component\Plugin\PluginInspectionInterface $plugin_instance
+   *
+   * @throws \Exception
+   */
+  public function validatePluginInstance(PluginInspectionInterface $plugin_instance);
+
+  /**
+   * Creates a plugin instance.
+   *
+   * @param string $plugin_id
+   * @param mixed[] $plugin_configuration
+   *
+   * @return \Drupal\Component\Plugin\PluginInspectionInterface|null
+   *   A plugin instance or NULL if there was no plugin ID.
+   */
+  public function createContainedPluginInstance($plugin_id, array $plugin_configuration = []);
+
+  /**
+   * Gets the instantiated plugin.
+   *
+   * @return \Drupal\Component\Plugin\PluginInspectionInterface|null
+   *   The plugin or NULL if no plugin was set yet.
+   */
+  public function getContainedPluginInstance();
+
+  /**
+   * Sets the instantiated plugin.
+   *
+   * @param \Drupal\Component\Plugin\PluginInspectionInterface $plugin_instance
+   *
+   * @return $this
+   */
+  public function setContainedPluginInstance(PluginInspectionInterface $plugin_instance);
+
+  /**
+   * Gets the plugin ID.
+   *
+   * @return string
+   */
+  public function getContainedPluginId();
+
+  /**
+   * Sets the plugin ID.
+   *
+   * @param string $plugin_id
+   *
+   * @return $this
+   */
+  public function setContainedPluginId($plugin_id);
+
+  /**
+   * Sets the plugin configuration.
+   *
+   * @return mixed[]
+   */
+  public function getContainedPluginConfiguration();
+
+  /**
+   * Sets the plugin configuration.
+   *
+   * @param mixed[] $plugin_configuration
+   *
+   * @return $this
+   */
+  public function setContainedPluginConfiguration(array $plugin_configuration);
+
+}
diff --git a/src/Plugin/Payment/LineItem/PaymentLineItemBase.php b/src/Plugin/Payment/LineItem/PaymentLineItemBase.php
index f61d9b5..9cedd2c 100644
--- a/src/Plugin/Payment/LineItem/PaymentLineItemBase.php
+++ b/src/Plugin/Payment/LineItem/PaymentLineItemBase.php
@@ -10,7 +10,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\currency\Math\MathInterface;
-use Drupal\payment\Entity\PaymentInterface;
+use Drupal\payment\PaymentAwareTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -21,6 +21,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 abstract class PaymentLineItemBase extends PluginBase implements PaymentLineItemInterface, ContainerFactoryPluginInterface {
 
+  use PaymentAwareTrait;
+
   /**
    * The math service.
    *
@@ -29,13 +31,6 @@ abstract class PaymentLineItemBase extends PluginBase implements PaymentLineItem
   protected $math;
 
   /**
-   * The payment this line item is for.
-   *
-   * @var \Drupal\payment\Entity\PaymentInterface
-   */
-  protected $payment;
-
-  /**
    * Constructs a new class instance.
    *
    * @param array $configuration
@@ -88,23 +83,7 @@ abstract class PaymentLineItemBase extends PluginBase implements PaymentLineItem
    * {@inheritdoc}
    */
   public function setConfiguration(array $configuration) {
-    $this->configuration = $configuration;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getPayment() {
-    return $this->payment;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setPayment(PaymentInterface $payment) {
-    $this->payment = $payment;
-
-    return $this;
+    $this->configuration = $configuration + $this->defaultConfiguration();
   }
 
   /**
diff --git a/src/Plugin/Payment/LineItem/PaymentLineItemInterface.php b/src/Plugin/Payment/LineItem/PaymentLineItemInterface.php
index 6feebbf..af8f135 100644
--- a/src/Plugin/Payment/LineItem/PaymentLineItemInterface.php
+++ b/src/Plugin/Payment/LineItem/PaymentLineItemInterface.php
@@ -10,27 +10,12 @@ use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\payment\Entity\PaymentInterface;
+use Drupal\payment\PaymentAwareInterface;
 
 /**
  * A payment line item.
  */
-interface PaymentLineItemInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PluginFormInterface {
-
-  /**
-   * Sets the payment the line item belongs to.
-   *
-   * @param \Drupal\payment\Entity\PaymentInterface $payment
-   *
-   * @return static
-   */
-  public function setPayment(PaymentInterface $payment);
-
-  /**
-   * Gets the payment this line item belongs to.
-   *
-   * @return \Drupal\payment\Entity\PaymentInterface
-   */
-  public function getPayment();
+interface PaymentLineItemInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PluginFormInterface, PaymentAwareInterface {
 
   /**
    * Gets the amount.
diff --git a/src/Plugin/Payment/Method/PaymentMethodBase.php b/src/Plugin/Payment/Method/PaymentMethodBase.php
index a5d02fd..7c0c04c 100644
--- a/src/Plugin/Payment/Method/PaymentMethodBase.php
+++ b/src/Plugin/Payment/Method/PaymentMethodBase.php
@@ -12,10 +12,10 @@ use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Utility\Token;
-use Drupal\payment\Entity\PaymentInterface;
 use Drupal\payment\PaymentExecutionResult;
 use Drupal\payment\Plugin\Payment\Status\PaymentStatusManagerInterface;
 use Drupal\payment\EventDispatcherInterface;
+use Drupal\payment\PaymentAwareTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -29,6 +29,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 abstract class PaymentMethodBase extends PluginBase implements ContainerFactoryPluginInterface, PaymentMethodInterface, PaymentMethodCapturePaymentInterface, PaymentMethodRefundPaymentInterface {
 
+  use PaymentAwareTrait;
+
   /**
    * The event dispatcher.
    *
@@ -44,20 +46,6 @@ abstract class PaymentMethodBase extends PluginBase implements ContainerFactoryP
   protected $moduleHandler;
 
   /**
-   * The payment this payment method is for.
-   *
-   * @var \Drupal\payment\Entity\PaymentInterface
-   */
-  protected $payment;
-
-  /**
-   * The payment status manager.
-   *
-   * @var \Drupal\payment\Plugin\Payment\Status\PaymentStatusManagerInterface
-   */
-  protected $paymentStatusManager;
-
-  /**
    * The token API.
    *
    * @var \Drupal\Core\Utility\Token
@@ -123,7 +111,7 @@ abstract class PaymentMethodBase extends PluginBase implements ContainerFactoryP
    * {@inheritdoc}
    */
   public function setConfiguration(array $configuration) {
-    $this->configuration = $configuration;
+    $this->configuration = $configuration + $this->defaultConfiguration();
   }
 
   /**
@@ -147,22 +135,6 @@ abstract class PaymentMethodBase extends PluginBase implements ContainerFactoryP
   /**
    * {@inheritdoc}
    */
-  public function getPayment() {
-    return $this->payment;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setPayment(PaymentInterface $payment) {
-    $this->payment = $payment;
-
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
     $message_text = $this->token->replace($this->getMessageText(), array(
       'payment' => $this->getPayment(),
diff --git a/src/Plugin/Payment/Method/PaymentMethodInterface.php b/src/Plugin/Payment/Method/PaymentMethodInterface.php
index 52bb998..3fca2de 100644
--- a/src/Plugin/Payment/Method/PaymentMethodInterface.php
+++ b/src/Plugin/Payment/Method/PaymentMethodInterface.php
@@ -11,6 +11,7 @@ use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\payment\Entity\PaymentInterface;
+use Drupal\payment\PaymentAwareInterface;
 
 /**
  * Defines a payment method.
@@ -26,7 +27,7 @@ use Drupal\payment\Entity\PaymentInterface;
  * - \Drupal\payment\Plugin\Payment\Method\PaymentMethodCapturePaymentInterface:
  *   This interface lets payment methods capture already authorized payments.
  */
-interface PaymentMethodInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PluginFormInterface {
+interface PaymentMethodInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PluginFormInterface, PaymentAwareInterface {
 
   /**
    * Checks if the payment can be executed.
@@ -62,22 +63,6 @@ interface PaymentMethodInterface extends PluginInspectionInterface, Configurable
   public function getPaymentExecutionResult();
 
   /**
-   * Gets the payment this payment method is for.
-   *
-   * @return \Drupal\payment\Entity\PaymentInterface
-   */
-  public function getPayment();
-
-  /**
-   * Gets the payment this payment method is for.
-   *
-   * @param \Drupal\payment\Entity\PaymentInterface $payment
-   *
-   * @return $this
-   */
-  public function setPayment(PaymentInterface $payment);
-
-  /**
    * Gets the plugin label.
    *
    * @return string
diff --git a/src/Plugin/Payment/MethodConfiguration/PaymentMethodConfigurationBase.php b/src/Plugin/Payment/MethodConfiguration/PaymentMethodConfigurationBase.php
index 7c245cf..3b25a0b 100644
--- a/src/Plugin/Payment/MethodConfiguration/PaymentMethodConfigurationBase.php
+++ b/src/Plugin/Payment/MethodConfiguration/PaymentMethodConfigurationBase.php
@@ -96,7 +96,7 @@ abstract class PaymentMethodConfigurationBase extends PluginBase implements Paym
    * {@inheritdoc}
    */
   public function setConfiguration(array $configuration) {
-    $this->configuration = $configuration;
+    $this->configuration = $configuration + $this->defaultConfiguration();
   }
 
   /**
diff --git a/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorBase.php b/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorBase.php
index 17bf30e..4577e41 100644
--- a/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorBase.php
+++ b/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorBase.php
@@ -11,6 +11,7 @@ use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\payment\Entity\PaymentInterface;
+use Drupal\payment\PaymentAwareTrait;
 use Drupal\payment\Plugin\Payment\Method\PaymentMethodInterface;
 use Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -23,6 +24,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 abstract class PaymentMethodSelectorBase extends PluginBase implements ContainerFactoryPluginInterface, PaymentMethodSelectorInterface {
 
+  use PaymentAwareTrait;
+
   /**
    * The current user.
    *
@@ -31,13 +34,6 @@ abstract class PaymentMethodSelectorBase extends PluginBase implements Container
   protected $currentUser;
 
   /**
-   * The payment a payment method is selected for.
-   *
-   * @var \Drupal\payment\Entity\PaymentInterface
-   */
-  protected $payment;
-
-  /**
    * The payment method manager.
    *
    * @var \Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface
@@ -169,13 +165,6 @@ abstract class PaymentMethodSelectorBase extends PluginBase implements Container
   /**
    * {@inheritdoc}
    */
-  public function getPayment() {
-    return $this->payment;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   public function setPayment(PaymentInterface $payment) {
     $this->payment = $payment;
     if ($payment->getPaymentMethod()) {
diff --git a/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorInterface.php b/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorInterface.php
index b34704e..642993d 100644
--- a/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorInterface.php
+++ b/src/Plugin/Payment/MethodSelector/PaymentMethodSelectorInterface.php
@@ -9,13 +9,13 @@ namespace Drupal\payment\Plugin\Payment\MethodSelector;
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
-use Drupal\payment\Entity\PaymentInterface;
+use Drupal\payment\PaymentAwareInterface;
 use Drupal\payment\Plugin\Payment\Method\PaymentMethodInterface;
 
 /**
  * Provides a plugin to select and configure a payment method for a payment.
  */
-interface PaymentMethodSelectorInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PluginFormInterface {
+interface PaymentMethodSelectorInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PluginFormInterface, PaymentAwareInterface {
 
   /**
    * Sets whether a payment method must be selected.
@@ -59,22 +59,6 @@ interface PaymentMethodSelectorInterface extends PluginInspectionInterface, Conf
   public function getAllowedPaymentMethods();
 
   /**
-   * Gets the payment this payment method is for.
-   *
-   * @return \Drupal\payment\Entity\PaymentInterface
-   */
-  public function getPayment();
-
-  /**
-   * Gets the payment this payment method is for.
-   *
-   * @param \Drupal\payment\Entity\PaymentInterface $payment
-   *
-   * @return $this
-   */
-  public function setPayment(PaymentInterface $payment);
-
-  /**
    * Gets the selected payment method.
    *
    * @return \Drupal\payment\Plugin\Payment\Method\PaymentMethodInterface
diff --git a/src/Plugin/Payment/Status/PaymentStatusBase.php b/src/Plugin/Payment/Status/PaymentStatusBase.php
index 75cb79b..17dd55c 100644
--- a/src/Plugin/Payment/Status/PaymentStatusBase.php
+++ b/src/Plugin/Payment/Status/PaymentStatusBase.php
@@ -9,6 +9,7 @@ namespace Drupal\payment\Plugin\Payment\Status;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginBase;
 use Drupal\payment\Entity\PaymentInterface;
+use Drupal\payment\PaymentAwareTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -19,12 +20,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 abstract class PaymentStatusBase extends PluginBase implements ContainerFactoryPluginInterface, PaymentStatusInterface {
 
-  /**
-   * The payment this payment status is for.
-   *
-   * @var \Drupal\payment\Entity\PaymentInterface
-   */
-  protected $payment;
+  use PaymentAwareTrait;
 
   /**
    * The payment status plugin manager.
@@ -85,7 +81,7 @@ abstract class PaymentStatusBase extends PluginBase implements ContainerFactoryP
    * {@inheritdoc}
    */
   public function setConfiguration(array $configuration) {
-    $this->configuration = $configuration;
+    $this->configuration = $configuration + $this->defaultConfiguration();
   }
 
   /**
@@ -107,38 +103,6 @@ abstract class PaymentStatusBase extends PluginBase implements ContainerFactoryP
   /**
    * {@inheritdoc}
    */
-  public function getPayment() {
-    return $this->payment;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setPayment(PaymentInterface $payment) {
-    $this->payment = $payment;
-
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setId($id) {
-    $this->configuration['id'] = $id;
-
-    return $this;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getId() {
-    return $this->configuration['id'];
-  }
-
-  /**
-   * {@inheritdoc}
-   */
   function getAncestors(){
     return $this->paymentStatusManager->getAncestors($this->getPluginId());
   }
diff --git a/src/Plugin/Payment/Status/PaymentStatusInterface.php b/src/Plugin/Payment/Status/PaymentStatusInterface.php
index 97e53af..d35908e 100644
--- a/src/Plugin/Payment/Status/PaymentStatusInterface.php
+++ b/src/Plugin/Payment/Status/PaymentStatusInterface.php
@@ -8,12 +8,12 @@ namespace Drupal\payment\Plugin\Payment\Status;
 
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Plugin\PluginInspectionInterface;
-use Drupal\payment\Entity\PaymentInterface;
+use Drupal\payment\PaymentAwareInterface;
 
 /**
  * A payment status plugin.
  */
-interface PaymentStatusInterface extends PluginInspectionInterface, ConfigurablePluginInterface {
+interface PaymentStatusInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PaymentAwareInterface {
 
   /**
    * Sets the created date and time.
@@ -34,38 +34,6 @@ interface PaymentStatusInterface extends PluginInspectionInterface, Configurable
   public function getCreated();
 
   /**
-   * Sets the payment the status belongs to.
-   *
-   * @param \Drupal\payment\Entity\PaymentInterface $payment
-   *
-   * @return static
-   */
-  public function setPayment(PaymentInterface $payment);
-
-  /**
-   * Gets the payment this status belongs to.
-   *
-   * @return \Drupal\payment\Entity\PaymentInterface
-   */
-  public function getPayment();
-
-  /**
-   * Sets the ID.
-   *
-   * @param int $id
-   * *
-   * @return static
-   */
-  public function setId($id);
-
-  /**
-   * Gets the ID.
-   *
-   * @return int
-   */
-  public function getId();
-
-  /**
    * Gets this payment status's ancestors.
    *
    * @return array
diff --git a/src/Plugin/Payment/Type/PaymentTypeBase.php b/src/Plugin/Payment/Type/PaymentTypeBase.php
index 4078bfe..baeb3a5 100644
--- a/src/Plugin/Payment/Type/PaymentTypeBase.php
+++ b/src/Plugin/Payment/Type/PaymentTypeBase.php
@@ -8,8 +8,8 @@ namespace Drupal\payment\Plugin\Payment\Type;
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginBase;
-use Drupal\payment\Entity\PaymentInterface;
 use Drupal\payment\EventDispatcherInterface;
+use Drupal\payment\PaymentAwareTrait;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -17,6 +17,8 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  */
 abstract class PaymentTypeBase extends PluginBase implements ContainerFactoryPluginInterface, PaymentTypeInterface {
 
+  use PaymentAwareTrait;
+
   /**
    * The event dispatcher.
    *
@@ -25,13 +27,6 @@ abstract class PaymentTypeBase extends PluginBase implements ContainerFactoryPlu
   protected $eventDispatcher;
 
   /**
-   * The payment this type is of.
-   *
-   * @var \Drupal\payment\Entity\PaymentInterface
-   */
-  protected $payment;
-
-  /**
    * Constructs a new class instance.
    *
    * @param array $configuration
@@ -81,23 +76,7 @@ abstract class PaymentTypeBase extends PluginBase implements ContainerFactoryPlu
    * {@inheritdoc}
    */
   public function setConfiguration(array $configuration) {
-    $this->configuration = $configuration;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getPayment() {
-    return $this->payment;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setPayment(PaymentInterface $payment) {
-    $this->payment = $payment;
-
-    return $this;
+    $this->configuration = $configuration + $this->defaultConfiguration();
   }
 
   /**
diff --git a/src/Plugin/Payment/Type/PaymentTypeInterface.php b/src/Plugin/Payment/Type/PaymentTypeInterface.php
index 98c330e..1844255 100644
--- a/src/Plugin/Payment/Type/PaymentTypeInterface.php
+++ b/src/Plugin/Payment/Type/PaymentTypeInterface.php
@@ -9,28 +9,12 @@ namespace Drupal\payment\Plugin\Payment\Type;
 use Drupal\Component\Plugin\ConfigurablePluginInterface;
 use Drupal\Component\Plugin\PluginInspectionInterface;
 use Drupal\Core\Session\AccountInterface;
-use Drupal\payment\Entity\PaymentInterface;
+use Drupal\payment\PaymentAwareInterface;
 
 /**
  * A payment type plugin.
  */
-interface PaymentTypeInterface extends PluginInspectionInterface, ConfigurablePluginInterface {
-
-  /**
-   * Sets the ID of the payment this plugin is of.
-   *
-   * @param \Drupal\payment\Entity\PaymentInterface $payment
-   *
-   * @return static
-   */
-  public function setPayment(PaymentInterface $payment);
-
-  /**
-   * Gets the ID of the payment this plugin is of.
-   *
-   * @return \Drupal\payment\Entity\PaymentInterface
-   */
-  public function getPayment();
+interface PaymentTypeInterface extends PluginInspectionInterface, ConfigurablePluginInterface, PaymentAwareInterface {
 
   /**
    * Returns the description of the payment this plugin is of.
diff --git a/src/QueueInterface.php b/src/QueueInterface.php
index 8064a81..e1f6c50 100644
--- a/src/QueueInterface.php
+++ b/src/QueueInterface.php
@@ -49,7 +49,7 @@ interface QueueInterface {
    *
    * @param integer $payment_id
    * @param string $acquisition_code
-   *   The code that was received from self::reserve().
+   *   The code that was received from self::claimPayment().
    *
    * @return bool
    *   Whether the acquisition was successful.
diff --git a/src/Tests/Entity/Payment/PaymentStorageWebTest.php b/src/Tests/Entity/Payment/PaymentStorageWebTest.php
index 39fdc64..1165f09 100644
--- a/src/Tests/Entity/Payment/PaymentStorageWebTest.php
+++ b/src/Tests/Entity/Payment/PaymentStorageWebTest.php
@@ -9,6 +9,8 @@ namespace Drupal\payment\Tests\Entity\Payment;
 
 use Drupal\payment\Entity\PaymentInterface;
 use Drupal\payment\Payment;
+use Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemInterface;
+use Drupal\payment\plugin\payment\status\PaymentStatusInterface;
 use Drupal\payment\Plugin\Payment\Type\PaymentTypeInterface;
 use Drupal\payment\Tests\Generate;
 use Drupal\simpletest\WebTestBase;
@@ -60,33 +62,23 @@ class PaymentStorageWebTest extends WebTestBase {
     $this->assertTrue(is_numeric($payment->getOwnerId()));
     // Check references to other tables.
     $payment_data = $database->select('payment', 'p')
-      ->fields('p', array('first_payment_status_id', 'last_payment_status_id'))
+      ->fields('p', array('first_payment_status_delta', 'last_payment_status_delta'))
       ->condition('id', $payment->id())
       ->execute()
       ->fetchAssoc();
-    $this->assertEqual($payment_data['first_payment_status_id'], 1);
-    $this->assertEqual($payment_data['last_payment_status_id'], 2);
+    $this->assertEqual($payment_data['first_payment_status_delta'], 0);
+    $this->assertEqual($payment_data['last_payment_status_delta'], 1);
     /** @var \Drupal\payment\Entity\PaymentInterface $payment_loaded */
     $payment_loaded = entity_load_unchanged('payment', $payment->id());
     $this->assertEqual(count($payment_loaded->getLineItems()), count($payment->getLineItems()));
+    foreach ($payment_loaded->getLineItems() as $line_item) {
+      $this->assertTrue($line_item instanceof PaymentLineItemInterface);
+    }
     $this->assertEqual(count($payment_loaded->getPaymentStatuses()), count($payment->getPaymentStatuses()));
-    $this->assertEqual($payment_loaded->getPaymentMethod()->getConfiguration(), $payment_method->getConfiguration());
-    $this->assertEqual($payment_loaded->getPaymentType()->getConfiguration(), $payment_type_configuration);
-
-    // Test deleting a payment.
-    $payment->delete();
-    $this->assertFalse(entity_load('payment', $payment->id()));
-    $line_items_exists = db_select('payment_line_item')
-      ->condition('payment_id', $payment->id())
-      ->countQuery()
-      ->execute()
-      ->fetchField();
-    $this->assertFalse($line_items_exists);
-    $statuses_exist = db_select('payment_status')
-      ->condition('payment_id', $payment->id())
-      ->countQuery()
-      ->execute()
-      ->fetchField();
-    $this->assertFalse($statuses_exist);
+    foreach ($payment_loaded->getPaymentStatuses() as $status) {
+      $this->assertTrue($status instanceof PaymentStatusInterface);
+    }
+    $this->assertEqual($payment_loaded->getPaymentMethod()->getConfiguration(), $payment->getPaymentMethod()->getConfiguration());
+    $this->assertEqual($payment_loaded->getPaymentType()->getConfiguration(), $payment->getPaymentType()->getConfiguration());
   }
 }
diff --git a/src/Tests/Entity/PaymentUnitTest.php b/src/Tests/Entity/PaymentUnitTest.php
index e1cd306..8fb55c6 100644
--- a/src/Tests/Entity/PaymentUnitTest.php
+++ b/src/Tests/Entity/PaymentUnitTest.php
@@ -127,7 +127,7 @@ class PaymentUnitTest extends KernelTestBase {
     $line_item_1->setName($this->randomMachineName());
     $line_item_2 = $this->lineItemManager->createInstance('payment_basic');
     $line_item_2->setName($this->randomMachineName());
-    $this->assertTrue(spl_object_hash($this->payment->setLineItems(array($line_item_1, $line_item_2))), spl_object_hash($this->payment));
+    $this->assertTrue(spl_object_hash($this->payment->setLineItems([$line_item_1, $line_item_2])), spl_object_hash($this->payment));
     $line_items = $this->payment->getLineItems();
     if ($this->assertTrue(is_array($line_items))) {
       $this->assertEqual(spl_object_hash($line_items[$line_item_1->getName()]), spl_object_hash($line_item_1));
@@ -147,23 +147,29 @@ class PaymentUnitTest extends KernelTestBase {
   }
 
   /**
-   * Tests setStatus() and getStatus().
+   * Tests setPaymentStatus() and getPaymentStatus().
    */
-  protected function testGetStatus() {
-    $status = $this->statusManager->createInstance('payment_pending');
-    $this->assertEqual(spl_object_hash($this->payment->setPaymentStatus($status, FALSE)), spl_object_hash($this->payment));
-    $this->assertEqual(spl_object_hash($this->payment->getPaymentStatus()), spl_object_hash($status));
+  protected function testGetPaymentStatus() {
+    $payment_status_a = $this->statusManager->createInstance('payment_pending');
+    $payment_status_b = $this->statusManager->createInstance('payment_failed');
+    $this->assertEqual(spl_object_hash($this->payment->setPaymentStatus($payment_status_a)), spl_object_hash($this->payment));
+    $this->assertEqual(spl_object_hash($this->payment->getPaymentStatus()), spl_object_hash($payment_status_a));
+    // Make sure we always get the last status.
+    $this->payment->setPaymentStatus($payment_status_b);
+    $this->assertEqual(spl_object_hash($this->payment->getPaymentStatus()), spl_object_hash($payment_status_b));
   }
 
   /**
-   * Tests setStatuses() and getStatuses().
+   * Tests setPaymentStatuses() and getPaymentStatuses().
    */
-  protected function testGetStatuses() {
+  protected function testGetPaymentStatuses() {
     $statuses = array($this->statusManager->createInstance('payment_pending'), $this->statusManager->createInstance('payment_failed'));
     $this->assertEqual(spl_object_hash($this->payment->setPaymentStatuses($statuses)), spl_object_hash($this->payment));
     $retrieved_statuses = $this->payment->getPaymentStatuses();
     $this->assertEqual(spl_object_hash(reset($retrieved_statuses)), spl_object_hash(reset($statuses)));
     $this->assertEqual(spl_object_hash(end($retrieved_statuses)), spl_object_hash(end($statuses)));
+    // Make sure we always get the last status.
+    $this->assertEqual(spl_object_hash($this->payment->getPaymentStatus()), spl_object_hash(end($statuses)));
   }
 
   /**
@@ -193,7 +199,8 @@ class PaymentUnitTest extends KernelTestBase {
     for ($i = 0; $i < 2; $i++) {
       /** @var \Drupal\payment\Plugin\Payment\LineItem\Basic $line_item */
       $line_item = $this->lineItemManager->createInstance('payment_basic');
-      $line_item->setName($this->randomMachineName());
+      $name = $this->randomMachineName();
+      $line_item->setName($name);
       $line_item->setAmount($amount);
       $line_item->setQuantity($quantity);
       $this->payment->setLineItem($line_item);
diff --git a/src/Tests/Plugin/Field/FieldType/PluginBagItemBaseTest.php b/src/Tests/Plugin/Field/FieldType/PluginBagItemBaseTest.php
new file mode 100644
index 0000000..a8ec91c
--- /dev/null
+++ b/src/Tests/Plugin/Field/FieldType/PluginBagItemBaseTest.php
@@ -0,0 +1,143 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\field\Tests\PluginBagItemBaseTest.
+ */
+
+namespace Drupal\payment\Tests\Plugin\Field\FieldType;
+
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin;
+use Drupal\payment_test\Plugin\PluginTest\MockManager;
+use Drupal\simpletest\KernelTestBase;
+
+/**
+ * Tests \Drupal\payment\Plugin\Field\Plugin\Field\FieldType\PluginBagItemBase.
+ *
+ * @group Payment
+ */
+class PluginBagItemBaseTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['payment', 'payment_test', 'plugin_test'];
+
+  /**
+   * The field item under test.
+   *
+   * @var \Drupal\payment\Plugin\Field\FieldType\PluginBagItemBase
+   */
+  protected $fieldItem;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $field_definition = BaseFieldDefinition::create('payment_test_plugin_bag');
+
+    $this->fieldItem = \Drupal::typedDataManager()->create($field_definition)[0];
+  }
+
+  /**
+   * Tests the field.
+   */
+  protected function testField() {
+    $plugin_id = 'payment_test_plugin';
+    $plugin_id_configurable = 'payment_test_configurable_plugin';
+    $plugin_configuration = [
+      'foo' => $this->randomMachineName()
+    ];
+
+    // Test default values.
+    $this->assertEqual($this->fieldItem->getContainedPluginId(), '');
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), []);
+    $this->assertNull($this->fieldItem->getContainedPluginInstance());
+
+    // Test setting values and auto-instantiation for a non-configurable plugin.
+    $this->fieldItem->setContainedPluginId($plugin_id);
+    $this->assertEqual($this->fieldItem->getContainedPluginId(), $plugin_id);
+    $this->fieldItem->setContainedPluginConfiguration($plugin_configuration);
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), []);
+    $this->assertEqual($this->fieldItem->getContainedPluginInstance()->getPluginId(), $plugin_id);
+
+    // Test setting values and auto-instantiation for a configurable plugin.
+    $this->fieldItem->setContainedPluginId($plugin_id_configurable);
+    $this->assertEqual($this->fieldItem->getContainedPluginId(), $plugin_id_configurable);
+    $this->fieldItem->setContainedPluginConfiguration($plugin_configuration);
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $plugin_configuration);
+    $this->assertEqual($this->fieldItem->getContainedPluginInstance()->getPluginId(), $plugin_id_configurable);
+    /** @var \Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin $plugin_instance_a */
+    $plugin_instance_a = $this->fieldItem->getContainedPluginInstance();
+    $this->assertTrue($plugin_instance_a instanceof MockConfigurablePlugin);
+    $this->assertEqual($plugin_instance_a->getConfiguration(), $plugin_configuration);
+    $altered_plugin_configuration = $plugin_configuration += [
+      'bar' => $this->randomMachineName(),
+    ];
+    $plugin_instance_a->setConfiguration($altered_plugin_configuration);
+    $this->assertEqual($plugin_instance_a->getConfiguration(), $altered_plugin_configuration);
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $altered_plugin_configuration);
+
+    // Test resetting the values.
+    $this->fieldItem->applyDefaultValue();
+    $this->assertEqual($this->fieldItem->getContainedPluginId(), '');
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), []);
+    $this->assertNull($this->fieldItem->getContainedPluginInstance());
+
+    // Test setting values again and auto-instantiation.
+    $this->fieldItem->applyDefaultValue();
+    $this->fieldItem->setContainedPluginId($plugin_id_configurable);
+    $this->assertEqual($this->fieldItem->getContainedPluginId(), $plugin_id_configurable);
+    $this->fieldItem->setContainedPluginConfiguration($plugin_configuration);
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $plugin_configuration);
+    /** @var \Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin $plugin_instance_b */
+    $plugin_instance_b = $this->fieldItem->getContainedPluginInstance();
+    $this->assertTrue($plugin_instance_b instanceof MockConfigurablePlugin);
+    $this->assertEqual($plugin_instance_b->getConfiguration(), $plugin_configuration);
+    // Make sure this is indeed a new instance and not the old one.
+    $this->assertNotIdentical(spl_object_hash($plugin_instance_b), spl_object_hash($plugin_instance_a));
+    // Make sure changing the configuration on the new instance changes the
+    // configuration in the field item.
+    $altered_plugin_configuration_a = $plugin_configuration + [
+      'bar' => $this->randomMachineName(),
+    ];
+    $altered_plugin_configuration_b = $plugin_configuration + [
+      'baz' => $this->randomMachineName(),
+    ];
+    $plugin_instance_b->setConfiguration($altered_plugin_configuration_b);
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $altered_plugin_configuration_b);
+    // Make sure changing the configuration on the old instance no longer has
+    // any effect on the field item.
+    $plugin_instance_a->setConfiguration($altered_plugin_configuration_a);
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $altered_plugin_configuration_b);
+
+    // Test feedback from the plugin back to the field item.
+    $plugin_manager = new MockManager();
+    /** @var \Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin $plugin_instance_c */
+    $plugin_configuration_c = $plugin_configuration + [
+        'qux' => $this->randomMachineName(),
+      ];
+    $plugin_instance_c = $plugin_manager->createInstance($plugin_id_configurable, $plugin_configuration_c);
+    $this->fieldItem->setContainedPluginInstance($plugin_instance_c);
+    $this->assertEqual(spl_object_hash($this->fieldItem->getContainedPluginInstance()), spl_object_hash($plugin_instance_c));
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $plugin_configuration_c);
+    $altered_plugin_configuration_c = $plugin_configuration_c + [
+        'foobar' => $this->randomMachineName(),
+      ];
+    $plugin_instance_c->setConfiguration($altered_plugin_configuration_c);
+    $this->assertEqual($this->fieldItem->getContainedPluginConfiguration(), $altered_plugin_configuration_c);
+
+    // Test setting the main property.
+    /** @var \Drupal\payment_test\Plugin\PluginTest\MockConfigurablePlugin $plugin_instance_d */
+    $plugin_instance_d = $plugin_manager->createInstance($plugin_id_configurable);
+    $plugin_instance_d->setConfiguration([
+      'oman' => '42',
+    ]);
+    $this->fieldItem->setValue($plugin_instance_d);
+    $this->assertEqual(spl_object_hash($this->fieldItem->getContainedPluginInstance()), spl_object_hash($plugin_instance_d));
+  }
+
+}
diff --git a/tests/src/Unit/Entity/Payment/PaymentStorageUnitTest.php b/tests/src/Unit/Entity/Payment/PaymentStorageUnitTest.php
index 7335839..adaf93b 100644
--- a/tests/src/Unit/Entity/Payment/PaymentStorageUnitTest.php
+++ b/tests/src/Unit/Entity/Payment/PaymentStorageUnitTest.php
@@ -54,20 +54,6 @@ class PaymentStorageUnitTest extends UnitTestCase {
   protected $languageManager;
 
   /**
-   * The payment line item manager.
-   *
-   * @var \Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface|\PHPUnit_Framework_MockObject_MockObject
-   */
-  protected $paymentLineItemManager;
-
-  /**
-   * The payment method manager.
-   *
-   * @var \Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface|\PHPUnit_Framework_MockObject_MockObject
-   */
-  protected $paymentMethodManager;
-
-  /**
    * The payment status manager.
    *
    * @var \Drupal\payment\Plugin\Payment\Status\PaymentStatusManagerInterface|\PHPUnit_Framework_MockObject_MockObject
@@ -106,15 +92,11 @@ class PaymentStorageUnitTest extends UnitTestCase {
 
     $this->languageManager = $this->getMock('\Drupal\Core\Language\LanguageManagerInterface');
 
-    $this->paymentLineItemManager = $this->getMock('\Drupal\payment\Plugin\Payment\LineItem\PaymentLineItemManagerInterface');
-
-    $this->paymentMethodManager = $this->getMock('\Drupal\payment\Plugin\Payment\Method\PaymentMethodManagerInterface');
-
     $this->paymentStatusManager= $this->getMock('\Drupal\payment\Plugin\Payment\Status\PaymentStatusManagerInterface');
 
     $this->paymentTypeManager = $this->getMock('\Drupal\payment\Plugin\Payment\Type\PaymentTypeManagerInterface');
 
-    $this->storage = new PaymentStorage($this->entityType, $this->database, $this->entityManager, $this->cacheBackend, $this->languageManager, $this->paymentLineItemManager, $this->paymentMethodManager, $this->paymentStatusManager, $this->paymentTypeManager);
+    $this->storage = new PaymentStorage($this->entityType, $this->database, $this->entityManager, $this->cacheBackend, $this->languageManager, $this->paymentStatusManager, $this->paymentTypeManager);
   }
 
   /**
@@ -127,8 +109,6 @@ class PaymentStorageUnitTest extends UnitTestCase {
       array('database', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->database),
       array('entity.manager', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->entityManager),
       array('language_manager', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->languageManager),
-      array('plugin.manager.payment.line_item', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->paymentLineItemManager),
-      array('plugin.manager.payment.method', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->paymentMethodManager),
       array('plugin.manager.payment.status', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->paymentStatusManager),
       array('plugin.manager.payment.type', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $this->paymentTypeManager),
     );
@@ -140,98 +120,4 @@ class PaymentStorageUnitTest extends UnitTestCase {
     $this->assertInstanceOf('\Drupal\payment\Entity\Payment\PaymentStorage', $storage);
   }
 
-  /**
-   * @covers ::mapToStorageRecord
-   */
-  public function testMapToStorageRecord() {
-    $bundle = $this->randomMachineName();
-    $currency_code = $this->randomMachineName();
-    $id = $this->randomMachineName();
-    $first_payment_status_id = mt_rand();
-    $last_payment_status_id = mt_rand();
-    $owner_id = mt_rand();
-    $uuid = $this->randomMachineName();
-    $payment_method_id = $this->randomMachineName();
-    $payment_method_configuration = array(
-      'foo' => $this->randomMachineName(),
-    );
-    $payment_type_id = $this->randomMachineName();
-    $payment_type_configuration = array(
-      'foo' => $this->randomMachineName(),
-    );
-
-    $first_payment_status = $this->getMock('\Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface');
-    $first_payment_status->expects($this->any())
-      ->method('getId')
-      ->will($this->returnValue($first_payment_status_id));
-    $last_payment_status = $this->getMock('\Drupal\payment\Plugin\Payment\Status\PaymentStatusInterface');
-    $last_payment_status->expects($this->any())
-      ->method('getId')
-      ->will($this->returnValue($last_payment_status_id));
-
-    $payment_method = $this->getMock('\Drupal\payment\Plugin\Payment\Method\PaymentMethodInterface');
-    $payment_method->expects($this->atLeastOnce())
-      ->method('getPluginId')
-      ->will($this->returnValue($payment_method_id));
-    $payment_method->expects($this->atLeastOnce())
-      ->method('getConfiguration')
-      ->will($this->returnValue($payment_method_configuration));
-
-    $payment_type = $this->getMock('\Drupal\payment\Plugin\Payment\Type\PaymentTypeInterface');
-    $payment_type->expects($this->atLeastOnce())
-      ->method('getPluginId')
-      ->will($this->returnValue($payment_type_id));
-    $payment_type->expects($this->atLeastOnce())
-      ->method('getConfiguration')
-      ->will($this->returnValue($payment_type_configuration));
-
-    $payment= $this->getMockBuilder('\Drupal\payment\Entity\Payment')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $payment->expects($this->atLeastOnce())
-      ->method('bundle')
-      ->will($this->returnValue($bundle));
-    $payment->expects($this->atLeastOnce())
-      ->method('getCurrencyCode')
-      ->will($this->returnValue($currency_code));
-    $payment->expects($this->atLeastOnce())
-      ->method('getOwnerId')
-      ->will($this->returnValue($owner_id));
-    $payment->expects($this->atLeastOnce())
-      ->method('getPaymentMethod')
-      ->will($this->returnValue($payment_method));
-    $payment->expects($this->atLeastOnce())
-      ->method('getPaymentType')
-      ->will($this->returnValue($payment_type));
-    $payment->expects($this->once())
-      ->method('getPaymentStatus')
-      ->will($this->returnValue($last_payment_status));
-    $payment->expects($this->once())
-      ->method('getPaymentStatuses')
-      ->will($this->returnValue(array($first_payment_status, $last_payment_status)));
-    $payment->expects($this->atLeastOnce())
-      ->method('id')
-      ->will($this->returnValue($id));
-    $payment->expects($this->atLeastOnce())
-      ->method('uuid')
-      ->will($this->returnValue($uuid));
-
-    $method = new \ReflectionMethod($this->storage, 'mapToStorageRecord');
-    $method->setAccessible(TRUE);
-
-    $record = $method->invoke($this->storage, $payment);
-    $this->assertInstanceOf('\stdClass', $record);
-    $this->assertSame($uuid, $record->uuid);
-    $this->assertSame($id, $record->id);
-    $this->assertSame($currency_code, $record->currency);
-    $this->assertSame($bundle, $record->bundle);
-    $this->assertSame($owner_id, $record->owner);
-    $this->assertSame($first_payment_status_id, $record->first_payment_status_id);
-    $this->assertSame($last_payment_status_id, $record->last_payment_status_id);
-    $this->assertSame($payment_method_id, $record->payment_method_id);
-    $this->assertSame(serialize($payment_method_configuration), $record->payment_method_configuration);
-    $this->assertSame($payment_type_id, $record->payment_type_id);
-    $this->assertSame(serialize($payment_type_configuration), $record->payment_type_configuration);
-  }
-
 }
diff --git a/tests/src/Unit/Plugin/Payment/LineItem/PaymentLineItemBaseUnitTest.php b/tests/src/Unit/Plugin/Payment/LineItem/PaymentLineItemBaseUnitTest.php
index ef3918c..1931a72 100644
--- a/tests/src/Unit/Plugin/Payment/LineItem/PaymentLineItemBaseUnitTest.php
+++ b/tests/src/Unit/Plugin/Payment/LineItem/PaymentLineItemBaseUnitTest.php
@@ -73,7 +73,7 @@ class PaymentLineItemBaseUnitTest extends UnitTestCase {
   public function testGetConfiguration() {
     $configuration = array(
       $this->randomMachineName() => mt_rand(),
-    );
+    ) + $this->lineItem->defaultConfiguration();
     $return = $this->lineItem->setConfiguration($configuration);
     $this->assertNull($return);
     $this->assertSame($configuration, $this->lineItem->getConfiguration());
diff --git a/tests/src/Unit/Plugin/Payment/MethodConfiguration/PaymentMethodConfigurationBaseUnitTest.php b/tests/src/Unit/Plugin/Payment/MethodConfiguration/PaymentMethodConfigurationBaseUnitTest.php
index e7c3a36..c0a9441 100644
--- a/tests/src/Unit/Plugin/Payment/MethodConfiguration/PaymentMethodConfigurationBaseUnitTest.php
+++ b/tests/src/Unit/Plugin/Payment/MethodConfiguration/PaymentMethodConfigurationBaseUnitTest.php
@@ -193,7 +193,7 @@ class PaymentMethodConfigurationBaseUnitTest extends UnitTestCase {
   public function testGetConfiguration() {
     $configuration = array(
       $this->randomMachineName() => $this->randomMachineName(),
-    );
+    ) + $this->paymentMethodConfiguration->defaultConfiguration();
     $return = $this->paymentMethodConfiguration->setConfiguration($configuration);
     $this->assertSame(NULL, $return);
     $this->assertSame($configuration, $this->paymentMethodConfiguration->getConfiguration());
diff --git a/tests/src/Unit/Plugin/Payment/Status/PaymentStatusBaseUnitTest.php b/tests/src/Unit/Plugin/Payment/Status/PaymentStatusBaseUnitTest.php
index 0fcdb31..41152b5 100644
--- a/tests/src/Unit/Plugin/Payment/Status/PaymentStatusBaseUnitTest.php
+++ b/tests/src/Unit/Plugin/Payment/Status/PaymentStatusBaseUnitTest.php
@@ -107,7 +107,7 @@ class PaymentStatusBaseUnitTest extends UnitTestCase {
   public function testGetConfiguration() {
     $configuration = array(
       $this->randomMachineName() => mt_rand(),
-    );
+    ) + $this->status->defaultConfiguration();
     $this->assertNull($this->status->setConfiguration($configuration));
     $this->assertSame($configuration, $this->status->getConfiguration());
   }
@@ -135,16 +135,6 @@ class PaymentStatusBaseUnitTest extends UnitTestCase {
   }
 
   /**
-   * @covers ::setId
-   * @covers ::getId
-   */
-  public function testGetId() {
-    $created = mt_rand();
-    $this->assertSame($this->status, $this->status->setId($created));
-    $this->assertSame($created, $this->status->getId());
-  }
-
-  /**
    * @covers ::getChildren
    */
   public function testGetChildren() {
