diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 5a8e96a..8079472 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -16,7 +16,7 @@ Ubercart 4.x
     * $order->product_count and uc_order_get_product_count() => $order->getProductCount()
     * $order address properties => $order->getAddress() and $order->setAddress()
     * $order->currency => $order->getCurrency()
-    * $order->payment_method => $order->getPaymentMethod() and $order->setPaymentMethod()
+    * $order->payment_method => $order->getPaymentMethodId() and $order->setPaymentMethodId()
     * uc_order_is_shippable() => $order->isShippable()
     * uc_order_log_changes($order_id, $changes) => $order->logChanges($changes)
     * uc_order_can_view_order() => $order->access('view')
diff --git a/payment/uc_authorizenet/uc_authorizenet.module b/payment/uc_authorizenet/uc_authorizenet.module
index efb92ed..df465e1 100644
--- a/payment/uc_authorizenet/uc_authorizenet.module
+++ b/payment/uc_authorizenet/uc_authorizenet.module
@@ -465,7 +465,7 @@ function _uc_authorizenet_charge($order, $amount, $data) {
     // Transaction information.
     'x_version' => '3.1',
     'x_type' => _uc_authorizenet_txn_map($data['txn_type']),
-    // 'x_method' => $order->getPaymentMethod() == 'credit' ? 'CC' : 'ECHECK',
+    // 'x_method' => $order->getPaymentMethodId() == 'credit' ? 'CC' : 'ECHECK',
     'x_method' => 'CC',
     // 'x_recurring_billing' => 'FALSE',
     'x_amount' => uc_currency_format($amount, FALSE, FALSE, '.'),
@@ -801,7 +801,7 @@ function uc_authorizenet_arb_create($order, $fee) {
   }
 
   // Add the payment information to the data array based on the payment method.
-  if ($order->getPaymentMethod() == 'credit') {
+  if ($order->getPaymentMethodId() == 'credit') {
     if ($order->payment_details['cc_exp_month'] < 10) {
       $order->payment_details['cc_exp_month'] = '0' . $order->payment_details['cc_exp_month'];
     }
diff --git a/payment/uc_credit/uc_credit.module b/payment/uc_credit/uc_credit.module
index afac5b8..0fb6e7d 100644
--- a/payment/uc_credit/uc_credit.module
+++ b/payment/uc_credit/uc_credit.module
@@ -200,7 +200,7 @@ function uc_credit_uc_store_status() {
  */
 function uc_credit_uc_order($op, $order, $arg2) {
   // Set up the encryption key and object for saving and loading.
-  if ($order->getPaymentMethod() == 'credit' && ($op == 'save' || $op == 'load')) {
+  if ($order->getPaymentMethodId() == 'credit' && ($op == 'save' || $op == 'load')) {
     // Log an error if encryption isn't configured properly.
     if (!uc_credit_encryption_key()) {
       watchdog('uc_credit', 'Credit card encryption must be set up to process credit cards.');
@@ -209,7 +209,7 @@ function uc_credit_uc_order($op, $order, $arg2) {
 
   switch ($op) {
     case 'submit':
-      if ($order->getPaymentMethod() == 'credit') {
+      if ($order->getPaymentMethodId() == 'credit') {
         // Clear out that session variable denoting this as a CC paid order.
         unset($_SESSION['cc_pay']);
 
@@ -233,13 +233,13 @@ function uc_credit_uc_order($op, $order, $arg2) {
       break;
 
     case 'save':
-      if ($order->getPaymentMethod() == 'credit' && !empty($order->payment_details)) {
+      if ($order->getPaymentMethodId() == 'credit' && !empty($order->payment_details)) {
         _uc_credit_save_cc_data_to_order($order->payment_details, $order->id());
       }
       break;
 
     case 'load':
-      if ($order->getPaymentMethod() == 'credit') {
+      if ($order->getPaymentMethodId() == 'credit') {
         // Load the CC details from the credit cache if available.
         $order->payment_details = uc_credit_cache('load');
 
diff --git a/payment/uc_cybersource/uc_cybersource.module b/payment/uc_cybersource/uc_cybersource.module
index 744d4ab..300396b 100644
--- a/payment/uc_cybersource/uc_cybersource.module
+++ b/payment/uc_cybersource/uc_cybersource.module
@@ -38,7 +38,7 @@ function uc_cybersource_page_alter(&$page) {
   if (isset($page[$block->region]['system_main']['#theme']) && $page[$block->region]['system_main']['#theme'] == 'uc_cart_checkout_review' && ($order_id = intval($_SESSION['cart_order'])) > 0) {
     $order = uc_order_load($order_id);
 
-    if ($order->getPaymentMethod() == 'cybersource_hop') {
+    if ($order->getPaymentMethodId() == 'cybersource_hop') {
       $page[$block->region]['system_main']['#form'] = drupal_get_form('uc_cybersource_hop_form', $order);
     }
   }
diff --git a/payment/uc_payment/lib/Drupal/uc_payment/Form/PaymentMethodSettingsForm.php b/payment/uc_payment/lib/Drupal/uc_payment/Form/PaymentMethodSettingsForm.php
index edb9ff1..dd044a7 100644
--- a/payment/uc_payment/lib/Drupal/uc_payment/Form/PaymentMethodSettingsForm.php
+++ b/payment/uc_payment/lib/Drupal/uc_payment/Form/PaymentMethodSettingsForm.php
@@ -25,11 +25,11 @@ class PaymentMethodSettingsForm extends ConfigFormBase {
    * {@inheritdoc}
    */
   public function buildForm(array $form, array &$form_state, $method = NULL) {
-    $form['#title'] = $this->t('!method settings', array('!method' => _uc_payment_method_data($method, 'name')));
+    $definition = \Drupal::service('plugin.manager.uc_payment.method')->getDefinition($method);
+    $form['#title'] = $this->t('!method settings', array('!method' => $definition['name']));
 
-    $callback = _uc_payment_method_data($method, 'callback');
-    $null = NULL;
-    $form = $callback('settings', $null, $form, $form_state);
+    $method = \Drupal::service('plugin.manager.uc_payment.method')->createInstance($method);
+    $form = $method->settingsForm($form, $form_state);
     $form['#submit'][] = array($this, 'submitForm');
     return parent::buildForm($form, $form_state);
   }
diff --git a/payment/uc_payment/lib/Drupal/uc_payment/PaymentMethodPluginBase.php b/payment/uc_payment/lib/Drupal/uc_payment/PaymentMethodPluginBase.php
new file mode 100644
index 0000000..5edfdab
--- /dev/null
+++ b/payment/uc_payment/lib/Drupal/uc_payment/PaymentMethodPluginBase.php
@@ -0,0 +1,24 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\uc_payment\PaymentMethodPluginBase.
+ */
+
+namespace Drupal\uc_payment;
+
+use Drupal\Core\Plugin\PluginBase;
+
+/**
+ * Defines a base payment method plugin implementation.
+ */
+abstract class PaymentMethodPluginBase extends PluginBase implements PaymentMethodPluginInterface {
+
+ /**
+   * {@inheritdoc}
+   */
+  function cartReviewTitle() {
+    return !empty($this->pluginDefinition['review']) ? $this->pluginDefinition['review'] : $this->pluginDefinition['name'];
+  }
+
+}
diff --git a/payment/uc_payment/lib/Drupal/uc_payment/PaymentMethodPluginInterface.php b/payment/uc_payment/lib/Drupal/uc_payment/PaymentMethodPluginInterface.php
new file mode 100644
index 0000000..8705ba3
--- /dev/null
+++ b/payment/uc_payment/lib/Drupal/uc_payment/PaymentMethodPluginInterface.php
@@ -0,0 +1,163 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\uc_payment\PaymentMethodPluginInterface.
+ */
+
+namespace Drupal\uc_payment;
+
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\uc_order\UcOrderInterface;
+
+/**
+ * Defines an interface for payment method plugins.
+ */
+interface PaymentMethodPluginInterface extends PluginInspectionInterface {
+
+  /**
+   * Returns the form or render array to be displayed at checkout.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order which is being processed.
+   * @param array $form
+   *   The checkout form array.
+   * @param array $form_state
+   *   The checkout form state array.
+   *
+   * @return array
+   *   A form or render array.
+   */
+  public function cartDetails(UcOrderInterface $order, array $form, array &$form_state);
+
+  /**
+   * Called when checkout is submitted with this payment method selected.
+   *
+   * Use this method to process any form elements output by the cartDetails()
+   * method.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order which is being processed.
+   * @param array $form
+   *   The checkout form array.
+   * @param array $form_state
+   *   The checkout form state array.
+   *
+   * @return bool
+   *   Return FALSE to abort the checkout process, or any other value to
+   *   continue the checkout process.
+   */
+  public function cartProcess(UcOrderInterface $order, array $form, array &$form_state);
+
+  /**
+   * Returns the payment method title to be used on the checkout review page.
+   *
+   * @return string
+   *   The payment method title.
+   */
+  public function cartReviewTitle();
+
+  /**
+   * Returns the payment method review details.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order that is being processed.
+   *
+   * @return array
+   */
+  public function cartReview(UcOrderInterface $order);
+
+  /**
+   * Called when an order is being deleted.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order that is being deleted.
+   */
+  public function orderDelete(UcOrderInterface $order);
+
+  /**
+   * Called when an order is being edited with this payment method.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order that is being edited.
+   *
+   * @return array
+   *   A form array.
+   */
+  public function orderEditDetails(UcOrderInterface $order);
+
+  /**
+   * Called when an order is being submitted after being edited.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order that is being edited.
+   * @param array $form
+   *   The form array.
+   * @param array $form_state
+   *   The form state array.
+   *
+   * @return array
+   *   An array of changes to log against the order.
+   */
+  public function orderEditProcess(UcOrderInterface $order, array $form, array $form_state);
+
+  /**
+   * Called when an order is being loaded with this payment method.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order that is being loaded.
+   */
+  public function orderLoad(UcOrderInterface $order);
+
+  /**
+   * Called when an order is being saved with this payment method.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order that is being saved.
+   */
+  public function orderSave(UcOrderInterface $order);
+
+  /**
+   * Called when an order is being submitted with this payment method.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order that is being submitted.
+   */
+  public function orderSubmit(UcOrderInterface $order);
+
+  /**
+   * Called when an order is being viewed by an administrator.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order that is being viewed.
+   *
+   * @return array
+   *   A render array.
+   */
+  public function orderView(UcOrderInterface $order);
+
+  /**
+   * Called when an order is being viewed by a customer.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order that is being viewed.
+   *
+   * @return array
+   *   A render array.
+   */
+  public function customerView(UcOrderInterface $order);
+
+  /**
+   * Form builder function for the payment method settings form.
+   *
+   * @param array $form
+   *   The form array.
+   * @param array $form_state
+   *   The form state array.
+   *
+   * @return array
+   *   The settings form.
+   */
+  public function settingsForm(array $form, array &$form_state);
+
+}
diff --git a/payment/uc_payment/lib/Drupal/uc_payment/Plugin/PaymentMethodManager.php b/payment/uc_payment/lib/Drupal/uc_payment/Plugin/PaymentMethodManager.php
index 86dfa0f..690384b 100644
--- a/payment/uc_payment/lib/Drupal/uc_payment/Plugin/PaymentMethodManager.php
+++ b/payment/uc_payment/lib/Drupal/uc_payment/Plugin/PaymentMethodManager.php
@@ -6,34 +6,40 @@
 
 namespace Drupal\uc_payment\Plugin;
 
-use Drupal\Component\Plugin\PluginManagerBase;
-use Drupal\Component\Plugin\Discovery\ProcessDecorator;
+use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Plugin\Discovery\AlterDecorator;
-use Drupal\Core\Plugin\Discovery\CacheDecorator;
-use Drupal\Core\Plugin\Discovery\HookDiscovery;
-use Drupal\Component\Plugin\Factory\DefaultFactory;
+use Drupal\Core\Language\LanguageManager;
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Drupal\uc_order\UcOrderInterface;
+use Drupal\uc_store\Plugin\Discovery\InfoHookDecorator;
 
 /**
  * Manages discovery and instantiation of payment methods.
  */
-class PaymentMethodManager extends PluginManagerBase {
+class PaymentMethodManager extends DefaultPluginManager {
 
   /**
-   * Constructs a new \Drupal\uc_payment\Plugin\PaymentMethodManager object.
+   * Constructs a PaymentMethodManager object.
    *
    * @param \Traversable $namespaces
    *   An object that implements \Traversable which contains the root paths
    *   keyed by the corresponding namespace to look for plugin implementations,
+   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+   *   Cache backend instance to use.
+   * @param \Drupal\Core\Language\LanguageManager $language_manager
+   *   The language manager.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
    *   The module handler.
    */
-  public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler) {
-    $this->discovery = new HookDiscovery($module_handler, 'uc_payment_method');
-    $this->discovery = new ProcessDecorator($this->discovery, array($this, 'processDefinition'));
-    $this->discovery = new AlterDecorator($this->discovery, 'uc_payment_method');
-    $this->discovery = new CacheDecorator($this->discovery, 'uc_payment:method');
-    $this->factory = new DefaultFactory($this->discovery);
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, LanguageManager $language_manager, ModuleHandlerInterface $module_handler) {
+    $this->discovery = new AnnotatedClassDiscovery('Plugin/Ubercart/PaymentMethod', $namespaces, 'Drupal\Component\Annotation\Plugin');
+    $this->discovery = new InfoHookDecorator($this->discovery, 'uc_payment_method', 'Drupal\uc_payment\Plugin\Ubercart\PaymentMethod\LegacyPaymentMethod');
+    $this->factory = new ContainerFactory($this);
+
+    $this->alterInfo($module_handler, 'uc_payment_method');
+    $this->setCacheBackend($cache_backend, $language_manager, 'uc_payment_methods');
   }
 
   /**
@@ -46,4 +52,17 @@ class PaymentMethodManager extends PluginManagerBase {
     $definition['weight'] = variable_get('uc_payment_method_' . $plugin_id . '_weight', $definition['weight']);
   }
 
+  /**
+   * Returns an instance of the payment method plugin for a specific order.
+   *
+   * @param \Drupal\uc_order\UcOrderInterface $order
+   *   The order from which the plugin should be instantiated.
+   *
+   * @return \Drupal\uc_payment\PaymentMethodPluginInterface
+   *   A fully configured plugin instance.
+   */
+  public function createFromOrder(UcOrderInterface $order) {
+    return $this->createInstance($order->getPaymentMethodId());
+  }
+
 }
diff --git a/payment/uc_payment/lib/Drupal/uc_payment/Plugin/Ubercart/PaymentMethod/LegacyPaymentMethod.php b/payment/uc_payment/lib/Drupal/uc_payment/Plugin/Ubercart/PaymentMethod/LegacyPaymentMethod.php
new file mode 100644
index 0000000..8d6fb81
--- /dev/null
+++ b/payment/uc_payment/lib/Drupal/uc_payment/Plugin/Ubercart/PaymentMethod/LegacyPaymentMethod.php
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\uc_payment\Plugin\Ubercart\PaymentMethod\LegacyPaymentMethod.
+ */
+
+namespace Drupal\uc_payment\Plugin\Ubercart\PaymentMethod;
+
+use Drupal\uc_order\UcOrderInterface;
+use Drupal\uc_payment\PaymentMethodPluginBase;
+
+/**
+ * Defines a payment method plugin implementation for legacy payment methods.
+ */
+class LegacyPaymentMethod extends PaymentMethodPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  function cartDetails(UcOrderInterface $order, array $form, array &$form_state) {
+    return $this->pluginDefinition['callback']('cart-details', $order, $form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function cartProcess(UcOrderInterface $order, array $form, array &$form_state) {
+    return $this->pluginDefinition['callback']('cart-process', $order, $form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function cartReview(UcOrderInterface $order) {
+    return $this->pluginDefinition['callback']('cart-review', $order);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function orderDelete(UcOrderInterface $order) {
+    return $this->pluginDefinition['callback']('order-delete', $order);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function orderEditDetails(UcOrderInterface $order) {
+    return $this->pluginDefinition['callback']('order-details', $order);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function orderEditProcess(UcOrderInterface $order, array $form, array $form_state) {
+    return $this->pluginDefinition['callback']('edit-process', $order, $form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function orderLoad(UcOrderInterface $order) {
+    return $this->pluginDefinition['callback']('order-load', $order);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function orderSave(UcOrderInterface $order) {
+    return $this->pluginDefinition['callback']('order-save', $order);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function orderSubmit(UcOrderInterface $order) {
+    return $this->pluginDefinition['callback']('order-submit', $order);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function orderView(UcOrderInterface $order) {
+    return $this->pluginDefinition['callback']('order-view', $order);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function customerView(UcOrderInterface $order) {
+    return $this->pluginDefinition['callback']('customer-view', $order);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function settingsForm(array $form, array &$form_state) {
+    $null = NULL;
+    return $this->pluginDefinition['callback']('settings', $null, $form, $form_state);
+  }
+
+}
diff --git a/payment/uc_payment/lib/Drupal/uc_payment/Plugin/views/field/Method.php b/payment/uc_payment/lib/Drupal/uc_payment/Plugin/views/field/Method.php
index 6e564c1..73b7cc5 100644
--- a/payment/uc_payment/lib/Drupal/uc_payment/Plugin/views/field/Method.php
+++ b/payment/uc_payment/lib/Drupal/uc_payment/Plugin/views/field/Method.php
@@ -24,7 +24,8 @@ class Method extends FieldPluginBase {
    */
   public function render(ResultRow $values) {
     $value = $this->getValue($values);
-    return $this->sanitizeValue(_uc_payment_method_data($value, 'name'));
+    $methods = _uc_payment_method_list();
+    return $this->sanitizeValue($methods[$value]['name']);
   }
 
 }
diff --git a/payment/uc_payment/uc_payment.module b/payment/uc_payment/uc_payment.module
index 739f224..dbf75b1 100644
--- a/payment/uc_payment/uc_payment.module
+++ b/payment/uc_payment/uc_payment.module
@@ -81,10 +81,11 @@ function uc_payment_form_uc_cart_view_form_alter(&$form, &$form_state) {
  */
 function uc_payment_form_uc_cart_checkout_review_form_alter(&$form, &$form_state) {
   $order = $form_state['uc_order'];
+  $definition = Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order)->getPluginDefinition();
 
-  if ($redirect = _uc_payment_method_data($order->getPaymentMethod(), 'redirect')) {
+  if (isset($definition['redirect'])) {
     unset($form['actions']['submit']);
-    $suffix = drupal_get_form($redirect, $order);
+    $suffix = drupal_get_form($definition['redirect'], $order);
     $form['#suffix'] = drupal_render($suffix);
   }
 }
@@ -95,23 +96,17 @@ function uc_payment_form_uc_cart_checkout_review_form_alter(&$form, &$form_state
 function uc_payment_uc_order($op, $order) {
   switch ($op) {
     case 'submit':
-      $func = _uc_payment_method_data($order->getPaymentMethod(), 'callback');
-      if (function_exists($func)) {
-        return $func('order-submit', $order);
-      }
-      break;
+      return Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order)->orderSubmit($order);
 
     case 'load':
-      $func = _uc_payment_method_data($order->getPaymentMethod(), 'callback');
-      if (function_exists($func)) {
-        $func('order-load', $order);
+      if ($order->getPaymentMethodId()) {
+        Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order)->orderLoad($order);
       }
       break;
 
     case 'save':
-      $func = _uc_payment_method_data($order->getPaymentMethod(), 'callback');
-      if (function_exists($func)) {
-        $func('order-save', $order);
+      if ($order->getPaymentMethodId()) {
+        Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order)->orderSave($order);
       }
       break;
 
@@ -130,10 +125,7 @@ function uc_payment_uc_order($op, $order) {
       // database.
       $methods = _uc_payment_method_list();
       foreach ($methods as $method) {
-        $func = $method['callback'];
-        if (function_exists($func)) {
-          $func('order-delete', $order);
-        }
+        Drupal::service('plugin.manager.uc_payment.method')->createInstance($method)->orderDelete($order);
       }
       break;
   }
@@ -278,7 +270,7 @@ function uc_payment_process_payment($method, $order_id, $amount, $data = NULL, $
   if (empty($gateways)) {
     // Display an error message if messages weren't silenced.
     if (!$default) {
-      drupal_set_message(t('You are not able to process %type payments.', array('%type' => _uc_payment_method_data($method, 'name'))));
+      drupal_set_message(t('You are not able to process %type payments.', array('%type' => $method)));
     }
 
     return FALSE;
@@ -377,11 +369,8 @@ function uc_payment_enter($order_id, $method, $amount, $uid = 0, $data = NULL, $
   $order = uc_order_load($order_id, TRUE);
   $account = user_load($uid);
 
-  $method_name = _uc_payment_method_data($method, 'review');
+  $method_name = Drupal::service('plugin.manager.uc_payment.method')->createInstance($method)->cartReviewTitle();
   if (empty($method_name)) {
-    $method_name = _uc_payment_method_data($method, 'name');
-  }
-  if (is_null($method_name)) {
     $method_name = t('Other');
   }
   if (is_array($data)) {
@@ -522,14 +511,6 @@ function _uc_payment_method_list() {
 }
 
 /**
- * Returns data from a payment method by method ID and the array key.
- */
-function _uc_payment_method_data($method_id, $key) {
-  $methods = _uc_payment_method_list();
-  return ($method_id && isset($methods[$method_id][$key])) ? $methods[$method_id][$key] : NULL;
-}
-
-/**
  * Builds a list of payment gateways defined in the enabled modules.
  */
 function _uc_payment_gateway_list($filter = NULL, $enabled_only = FALSE) {
diff --git a/payment/uc_payment/uc_payment.services.yml b/payment/uc_payment/uc_payment.services.yml
index 753dfd9..ebf4251 100644
--- a/payment/uc_payment/uc_payment.services.yml
+++ b/payment/uc_payment/uc_payment.services.yml
@@ -1,4 +1,4 @@
 services:
   plugin.manager.uc_payment.method:
     class: Drupal\uc_payment\Plugin\PaymentMethodManager
-    arguments: ['@container.namespaces', '@module_handler']
+    parent: default_plugin_manager
diff --git a/payment/uc_payment/uc_payment.tokens.inc b/payment/uc_payment/uc_payment.tokens.inc
index f9db95e..2288355 100644
--- a/payment/uc_payment/uc_payment.tokens.inc
+++ b/payment/uc_payment/uc_payment.tokens.inc
@@ -34,10 +34,7 @@ function uc_payment_tokens($type, $tokens, $data = array(), $options = array())
 
     if (isset($tokens['payment-method'])) {
       $original = $tokens['payment-method'];
-      $values[$original] = _uc_payment_method_data($order->getPaymentMethod(), 'review');
-      if (empty($values[$original])) {
-        $values[$original] = _uc_payment_method_data($order->getPaymentMethod(), 'name');
-      }
+      $values[$original] = Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order)->cartReviewTitle();
     }
 
     if (isset($tokens['payment-balance'])) {
diff --git a/payment/uc_payment/uc_payment_checkout_pane.inc b/payment/uc_payment/uc_payment_checkout_pane.inc
index 71da683..4ec1372 100644
--- a/payment/uc_payment/uc_payment_checkout_pane.inc
+++ b/payment/uc_payment/uc_payment_checkout_pane.inc
@@ -52,8 +52,8 @@ function uc_checkout_pane_payment($op, &$order, $form = NULL, &$form_state = NUL
         $description = t('Select a payment method from the following options.');
       }
 
-      if (!$order->getPaymentMethod() || !isset($options[$order->getPaymentMethod()])) {
-        $order->setPaymentMethod(key($options));
+      if (!$order->getPaymentMethodId() || !isset($options[$order->getPaymentMethodId()])) {
+        $order->setPaymentMethodId(key($options));
       }
 
       $contents['payment_method'] = array(
@@ -61,7 +61,7 @@ function uc_checkout_pane_payment($op, &$order, $form = NULL, &$form_state = NUL
         '#title' => t('Payment method'),
         '#title_display' => 'invisible',
         '#options' => $options,
-        '#default_value' => $order->getPaymentMethod(),
+        '#default_value' => $order->getPaymentMethodId(),
         '#disabled' => count($options) == 1,
         '#required' => TRUE,
         '#ajax' => array(
@@ -74,13 +74,13 @@ function uc_checkout_pane_payment($op, &$order, $form = NULL, &$form_state = NUL
       );
 
       $contents['details'] = array(
-        '#prefix' => '<div id="payment-details" class="clearfix payment-details-' . $order->getPaymentMethod() . '">',
+        '#prefix' => '<div id="payment-details" class="clearfix payment-details-' . $order->getPaymentMethodId() . '">',
         '#markup' => t('Continue with checkout to complete payment.'),
         '#suffix' => '</div>',
       );
 
-      $func = _uc_payment_method_data($order->getPaymentMethod(), 'callback');
-      if (function_exists($func) && $details = $func('cart-details', $order, $form, $form_state)) {
+      $details = Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order)->cartDetails($order, $form, $form_state);
+      if ($details) {
         unset($contents['details']['#markup']);
         $contents['details'] += $details;
       }
@@ -92,32 +92,20 @@ function uc_checkout_pane_payment($op, &$order, $form = NULL, &$form_state = NUL
         form_set_error('panes][payment][payment_method', $form_state, t('You cannot check out without selecting a payment method.'));
         return FALSE;
       }
-      $order->setPaymentMethod($form_state['values']['panes']['payment']['payment_method']);
-      $func = _uc_payment_method_data($order->getPaymentMethod(), 'callback');
-      if (function_exists($func)) {
-        $result = $func('cart-process', $order, $form, $form_state);
-        if ($result === FALSE) {
-          return FALSE;
-        }
-      }
-      return TRUE;
+      $order->setPaymentMethodId($form_state['values']['panes']['payment']['payment_method']);
+      $result = Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order)->cartProcess($order, $form, $form_state);
+      return $result !== FALSE;
 
     case 'review':
       $line_items = uc_order_load_line_items_display($order);
       foreach ($line_items as $line_item) {
         $review[] = array('title' => $line_item['title'], 'data' => theme('uc_price', array('price' => $line_item['amount'])));
       }
-      $review_data = _uc_payment_method_data($order->getPaymentMethod(), 'review');
-      if (empty($review_data)) {
-        $review_data = _uc_payment_method_data($order->getPaymentMethod(), 'name');
-      }
-      $review[] = array('border' => 'top', 'title' => t('Paying by'), 'data' => $review_data);
-      $func = _uc_payment_method_data($order->getPaymentMethod(), 'callback');
-      if (function_exists($func)) {
-        $result = $func('cart-review', $order);
-        if (is_array($result)) {
-          $review = array_merge($review, $result);
-        }
+      $method = Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order);
+      $review[] = array('border' => 'top', 'title' => t('Paying by'), 'data' => $method->cartReviewTitle());
+      $result = $method->cartReview($order);
+      if (is_array($result)) {
+        $review = array_merge($review, $result);
       }
       return $review;
 
diff --git a/payment/uc_payment/uc_payment_order_pane.inc b/payment/uc_payment/uc_payment_order_pane.inc
index 8474d81..e03e989 100644
--- a/payment/uc_payment/uc_payment_order_pane.inc
+++ b/payment/uc_payment/uc_payment_order_pane.inc
@@ -30,40 +30,30 @@ function uc_order_pane_payment($op, $order, &$form = NULL, &$form_state = NULL)
         );
       }
 
-      $method_name = _uc_payment_method_data($order->getPaymentMethod(), 'review');
-      if (empty($method_name)) {
-        $method_name = _uc_payment_method_data($order->getPaymentMethod(), 'name');
-      }
+      $method = Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order);
       $build['method'] = array(
-        '#markup' => t('Method: @payment_method', array('@payment_method' => $method_name)),
+        '#markup' => t('Method: @payment_method', array('@payment_method' => $method->cartReviewTitle())),
         '#prefix' => '<br />',
       );
-      $func = _uc_payment_method_data($order->getPaymentMethod(), 'callback');
-      if (function_exists($func)) {
-        $method_output = $func('order-view', $order);
-        if (!empty($method_output)) {
-          $build['output'] = $method_output + array(
-            '#prefix' => '<br />',
-          );
-        }
+
+      $method_output = $method->orderView($order);
+      if (!empty($method_output)) {
+        $build['output'] = $method_output + array(
+          '#prefix' => '<br />',
+        );
       }
 
       return $build;
 
     case 'customer':
-      $method_name = _uc_payment_method_data($order->getPaymentMethod(), 'review');
-      if (empty($method_name)) {
-        $method_name = _uc_payment_method_data($order->getPaymentMethod(), 'name');
-      }
-      $build['method'] = array('#markup' => t('Method: @payment_method', array('@payment_method' => $method_name)));
-      $func = _uc_payment_method_data($order->getPaymentMethod(), 'callback');
-      if (function_exists($func)) {
-        $method_output = $func('customer-view', $order);
-        if (!empty($method_output)) {
-          $build['output'] = $method_output + array(
-            '#prefix' => '<br />',
-          );
-        }
+      $method = Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order);
+      $build['method'] = array('#markup' => t('Method: @payment_method', array('@payment_method' => $method->cartReviewTitle())));
+
+      $method_output = $method->customerView($order);
+      if (!empty($method_output)) {
+        $build['output'] = $method_output + array(
+          '#prefix' => '<br />',
+        );
       }
 
       return $build;
@@ -77,7 +67,7 @@ function uc_order_pane_payment($op, $order, &$form = NULL, &$form_state = NULL)
       $form['payment']['payment_method'] = array(
         '#type' => 'select',
         '#title' => t('Payment method'),
-        '#default_value' => $order->getPaymentMethod(),
+        '#default_value' => $order->getPaymentMethodId(),
         '#options' => !empty($options) ? $options : array(t('None available')),
         '#disabled' => empty($options),
         '#ajax' => array(
@@ -93,9 +83,9 @@ function uc_order_pane_payment($op, $order, &$form = NULL, &$form_state = NULL)
         '#suffix' => '</div>',
       );
 
-      $method = isset($form_state['values']['payment_method']) ? $form_state['values']['payment_method'] : $order->getPaymentMethod();
-      $func = _uc_payment_method_data($method, 'callback');
-      if (function_exists($func) && $details = $func('order-details', $order)) {
+      $method = isset($form_state['values']['payment_method']) ? $form_state['values']['payment_method'] : $order->getPaymentMethodId();
+      $details = Drupal::service('plugin.manager.uc_payment.method')->createInstance($method)->orderEditDetails($order);
+      if ($details) {
         if (is_array($details)) {
           $form['payment']['payment_details'] += $details;
         }
@@ -111,14 +101,15 @@ function uc_order_pane_payment($op, $order, &$form = NULL, &$form_state = NULL)
     case 'edit-process':
       $changes['payment_method'] = $form_state['values']['payment_method'];
       $changes['payment_details'] = isset($form_state['values']['payment_details']) ? $form_state['values']['payment_details'] : array();
-      $func = _uc_payment_method_data($form_state['values']['payment_method'], 'callback');
-      if (function_exists($func) && ($return = $func('edit-process', $order, $form, $form_state)) != NULL && is_array($return)) {
+
+      $order->setPaymentMethodId($changes['payment_method']);
+      $method = Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order);
+      $return = $method->orderEditProcess($order, $form, $form_state);
+      if (is_array($return)) {
         $changes['payment_details'] = array_merge($changes['payment_details'], $return);
       }
+      $order->payment_details = $changes['payment_details'];
 
-      if (!isset($order->payment_details)) {
-        $order->payment_details = array();
-      }
       return $changes;
   }
 }
diff --git a/payment/uc_payment_pack/uc_payment_pack.module b/payment/uc_payment_pack/uc_payment_pack.module
index b92fb72..747eb41 100644
--- a/payment/uc_payment_pack/uc_payment_pack.module
+++ b/payment/uc_payment_pack/uc_payment_pack.module
@@ -179,7 +179,7 @@ function uc_payment_method_cod($op, &$order, $form = NULL, $form_state = NULL) {
       break;
 
     case 'order-submit':
-      if ($order->getPaymentMethod() == 'cod' &&
+      if ($order->getPaymentMethodId() == 'cod' &&
           ($max = $cod_config->get('max_order')) > 0 &&
           is_numeric($max) &&
           $order->getTotal() > $max) {
diff --git a/payment/uc_paypal/uc_paypal.pages.inc b/payment/uc_paypal/uc_paypal.pages.inc
index 779eb69..07c1577 100644
--- a/payment/uc_paypal/uc_paypal.pages.inc
+++ b/payment/uc_paypal/uc_paypal.pages.inc
@@ -88,7 +88,7 @@ function uc_paypal_ipn() {
 
     $duplicate = (bool) db_query_range('SELECT 1 FROM {uc_payment_paypal_ipn} WHERE txn_id = :id AND status <> :status', 0, 1, array(':id' => $txn_id, ':status' => 'Pending'))->fetchField();
     if ($duplicate) {
-      if ($order->getPaymentMethod() != 'credit') {
+      if ($order->getPaymentMethodId() != 'credit') {
         watchdog('uc_paypal', 'IPN transaction ID has been processed before.', array(), WATCHDOG_NOTICE);
       }
       return;
@@ -243,7 +243,7 @@ function uc_paypal_ec_review() {
     if (!$order->getEmail()) {
       $order->setEmail($nvp_response['EMAIL']);
     }
-    $order->setPaymentMethod('paypal_ec');
+    $order->setPaymentMethodId('paypal_ec');
 
     $order->save();
 
@@ -423,7 +423,7 @@ function uc_paypal_complete($order) {
   }
 
   // Ensure the payment method is PayPal WPS.
-  if ($order->getPaymentMethod() != 'paypal_wps') {
+  if ($order->getPaymentMethodId() != 'paypal_wps') {
     drupal_goto('cart');
   }
 
diff --git a/shipping/uc_shipping/uc_shipping.module b/shipping/uc_shipping/uc_shipping.module
index 47608bc..7186e23 100644
--- a/shipping/uc_shipping/uc_shipping.module
+++ b/shipping/uc_shipping/uc_shipping.module
@@ -265,11 +265,7 @@ function template_preprocess_uc_packing_slip(&$variables) {
   $variables['shipping_phone'] = check_plain($order->getAddress('delivery')->phone);
 
   if (module_exists('uc_payment')) {
-    $payment_method = _uc_payment_method_data($order->getPaymentMethod(), 'review');
-    if (empty($payment_method)) {
-      $payment_method = _uc_payment_method_data($order->getPaymentMethod(), 'name');
-    }
-    $variables['payment_method'] = $payment_method;
+    $variables['payment_method'] = Drupal::service('plugin.manager.uc_payment.method')->createFromOrder($order)->cartReviewTitle();
   }
   else {
     $variables['payment_method'] = '';
diff --git a/uc_order/lib/Drupal/uc_order/Entity/UcOrder.php b/uc_order/lib/Drupal/uc_order/Entity/UcOrder.php
index aedfe1f..d1a76ed 100644
--- a/uc_order/lib/Drupal/uc_order/Entity/UcOrder.php
+++ b/uc_order/lib/Drupal/uc_order/Entity/UcOrder.php
@@ -289,14 +289,14 @@ class UcOrder extends ContentEntityBase implements UcOrderInterface {
   /**
    * {@inheritdoc}
    */
-  public function getPaymentMethod() {
+  public function getPaymentMethodId() {
     return $this->get('payment_method')->value;
   }
 
   /**
    * {@inheritdoc}
    */
-  public function setPaymentMethod($payment_method) {
+  public function setPaymentMethodId($payment_method) {
     $this->set('payment_method', $payment_method);
     return $this;
   }
diff --git a/uc_order/lib/Drupal/uc_order/UcOrderInterface.php b/uc_order/lib/Drupal/uc_order/UcOrderInterface.php
index a5d09ab..b52b9f3 100644
--- a/uc_order/lib/Drupal/uc_order/UcOrderInterface.php
+++ b/uc_order/lib/Drupal/uc_order/UcOrderInterface.php
@@ -134,7 +134,7 @@ interface UcOrderInterface extends ContentEntityInterface {
    * @return string
    *   The payment method.
    */
-  public function getPaymentMethod();
+  public function getPaymentMethodId();
 
   /**
    * Sets the order payment method.
@@ -145,7 +145,7 @@ interface UcOrderInterface extends ContentEntityInterface {
    * @return \Drupal\uc_order\UcOrderInterface
    *   The called owner entity.
    */
-  public function setPaymentMethod($payment_method);
+  public function setPaymentMethodId($payment_method);
 
   /**
    * Returns an address attached to the order.
diff --git a/uc_store/lib/Drupal/uc_store/Plugin/Discovery/InfoHookDecorator.php b/uc_store/lib/Drupal/uc_store/Plugin/Discovery/InfoHookDecorator.php
new file mode 100644
index 0000000..ca5001d
--- /dev/null
+++ b/uc_store/lib/Drupal/uc_store/Plugin/Discovery/InfoHookDecorator.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\uc_store\Plugin\Discovery\InfoHookDecorator.
+ */
+
+namespace Drupal\uc_store\Plugin\Discovery;
+
+use Drupal\Core\Plugin\Discovery\InfoHookDecorator as BaseInfoHookDecorator;
+
+/**
+ * Allows info hook implementations to enhance discovered plugin definitions.
+ */
+class InfoHookDecorator extends BaseInfoHookDecorator {
+
+  /**
+   * The name of the class that will be instantiated for legacy plugins.
+   *
+   * @var string
+   */
+  protected $legacyClass;
+
+  /**
+   * Constructs a InfoHookDecorator object.
+   *
+   * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $decorated
+   *   The object implementing DiscoveryInterface that is being decorated.
+   * @param string $hook
+   *   The name of the info hook to be invoked by this discovery instance.
+   * @param string $class
+   *   The name of the class to be instantiated for legacy plugins.
+   */
+  public function __construct(DiscoveryInterface $decorated, $hook, $class) {
+    $this->decorated = $decorated;
+    $this->hook = $hook;
+    $this->legacyClass = $class;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDefinitions() {
+    $definitions = $this->decorated->getDefinitions();
+    foreach (\Drupal::moduleHandler()->getImplementations($this->hook) as $module) {
+      $function = $module . '_' . $this->hook;
+      $result = $function($definitions);
+      if (is_array($result)) {
+        foreach ($result as $plugin_id => $definition) {
+          $definition += array(
+            'id' => $plugin_id,
+            'provider' => $module,
+            'class' => $this->legacyClass,
+          );
+          $definitions[$definition['id']] = $definition;
+        }
+      }
+    }
+    return $definitions;
+  }
+
+}
