diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 8383bb5..bc9df7a 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -52,8 +52,8 @@ Ubercart 4.x
     * _uc_payment_method_list() => uc_payment_method_list()
     * _uc_payment_method_data() removed
 * Checkout panes are plugins
-    * hook_uc_checkout_pane() is still supported but can be converted to CheckoutPanePluginInterface plugins
     * plugin.manager.uc_cart.checkout_pane service (CheckoutPaneManager) manages the available plugins
+    * hook_uc_checkout_pane() removed, hook_uc_checkout_pane_alter() is still supported
     * _uc_checkout_pane_list() and _uc_checkout_pane_data() removed
 
 
diff --git a/uc_cart/src/CheckoutPanePluginInterface.php b/uc_cart/src/CheckoutPanePluginInterface.php
index 67a6b79..ecb4c62 100644
--- a/uc_cart/src/CheckoutPanePluginInterface.php
+++ b/uc_cart/src/CheckoutPanePluginInterface.php
@@ -14,6 +14,11 @@ use Drupal\uc_order\OrderInterface;
 
 /**
  * Defines an interface for checkout pane plugins.
+ *
+ * The checkout screen for Ubercart is a compilation of enabled checkout panes.
+ * A checkout pane can be used to display order information, collect data from
+ * the customer, or interact with other panes. Panes are defined in enabled
+ * modules as plugins that implement this interface.
  */
 interface CheckoutPanePluginInterface extends PluginInspectionInterface, ConfigurablePluginInterface {
 
@@ -24,7 +29,7 @@ interface CheckoutPanePluginInterface extends PluginInspectionInterface, Configu
    *   The order that is being processed.
    * @param array $form
    *   The checkout form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The checkout form state array.
    */
   public function prepare(OrderInterface $order, array $form, FormStateInterface $form_state);
@@ -36,11 +41,12 @@ interface CheckoutPanePluginInterface extends PluginInspectionInterface, Configu
    *   The order that is being processed.
    * @param array $form
    *   The checkout form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The checkout form state array.
    *
    * @return array
-   *   A form array.
+   *   A form array, with an optional '#description' key to provide help text
+   *   for the pane.
    */
   public function view(OrderInterface $order, array $form, FormStateInterface $form_state);
 
@@ -51,11 +57,11 @@ interface CheckoutPanePluginInterface extends PluginInspectionInterface, Configu
    *   The order that is being processed.
    * @param array $form
    *   The checkout form array.
-   * @param array $form_state
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The checkout form state array.
    *
    * @return bool
-   *   TRUE if the pane is valid, FALSE otherwise..
+   *   TRUE if the pane is valid, FALSE otherwise.
    */
   public function process(OrderInterface $order, array $form, FormStateInterface $form_state);
 
@@ -66,7 +72,8 @@ interface CheckoutPanePluginInterface extends PluginInspectionInterface, Configu
    *   The order that is being processed.
    *
    * @return array
-   *   A checkout review array.
+   *   A checkout review array. Each item contains contains "title" and "data"
+   *   keys which have HTML to be displayed on the checkout review page.
    */
   public function review(OrderInterface $order);
 
@@ -79,7 +86,7 @@ interface CheckoutPanePluginInterface extends PluginInspectionInterface, Configu
   public function settingsForm();
 
   /**
-   * Returns the title of the checkout pane.
+   * Returns the title of the pane, to be displayed on the checkout form.
    *
    * @return string
    *   The pane title.
diff --git a/uc_cart/src/Plugin/CheckoutPaneManager.php b/uc_cart/src/Plugin/CheckoutPaneManager.php
index bbffcc7..8e6dda3 100644
--- a/uc_cart/src/Plugin/CheckoutPaneManager.php
+++ b/uc_cart/src/Plugin/CheckoutPaneManager.php
@@ -10,9 +10,8 @@ namespace Drupal\uc_cart\Plugin;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
-use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
-use Drupal\Core\Plugin\Factory\ContainerFactory;
-use Drupal\uc_store\Plugin\Discovery\InfoHookDecorator;
+use Drupal\uc_cart\Annotation\CheckoutPane;
+use Drupal\uc_cart\CheckoutPanePluginInterface;
 
 /**
  * Manages discovery and instantiation of checkout panes.
@@ -44,12 +43,8 @@ class CheckoutPaneManager extends DefaultPluginManager {
    *   The module handler.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    $this->discovery = new AnnotatedClassDiscovery('Plugin/Ubercart/CheckoutPane', $namespaces, 'Drupal\uc_cart\Annotation\CheckoutPane');
-    $this->discovery = new InfoHookDecorator($this->discovery, 'uc_checkout_pane', 'Drupal\uc_cart\Plugin\Ubercart\CheckoutPane\LegacyCheckoutPane');
-    $this->factory = new ContainerFactory($this);
-
-    $this->moduleHandler = $module_handler;
-    $this->alterInfo('uc_checkout_pane');
+    parent::__construct('Plugin/Ubercart/CheckoutPane', $namespaces, $module_handler, CheckoutPanePluginInterface::class, CheckoutPane::class);
+    $this->alterInfo('payment_method');
     $this->setCacheBackend($cache_backend, 'uc_checkout_panes');
 
     $this->paneConfig = \Drupal::config('uc_cart.settings')->get('panes');
diff --git a/uc_cart/src/Plugin/Ubercart/CheckoutPane/LegacyCheckoutPane.php b/uc_cart/src/Plugin/Ubercart/CheckoutPane/LegacyCheckoutPane.php
deleted file mode 100644
index 7013fb5..0000000
--- a/uc_cart/src/Plugin/Ubercart/CheckoutPane/LegacyCheckoutPane.php
+++ /dev/null
@@ -1,62 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\uc_cart\Plugin\Ubercart\CheckoutPane\LegacyCheckoutPane.
- */
-
-namespace Drupal\uc_cart\Plugin\Ubercart\CheckoutPane;
-
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\uc_cart\CheckoutPanePluginBase;
-use Drupal\uc_order\OrderInterface;
-
-/**
- * Defines a plugin implementation for legacy checkout panes.
- */
-class LegacyCheckoutPane extends CheckoutPanePluginBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function prepare(OrderInterface $order, array $form, FormStateInterface $form_state) {
-    $this->pluginDefinition['callback']('prepare', $order, $form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function view(OrderInterface $order, array $form, FormStateInterface $form_state) {
-    $pane = $this->pluginDefinition['callback']('view', $order, $form, $form_state);
-
-    $build = $pane['contents'];
-    if (isset($pane['description'])) {
-      $build['#description'] = $pane['description'];
-    }
-
-    return $build;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function process(OrderInterface $order, array $form, FormStateInterface $form_state) {
-    $this->pluginDefinition['callback']('process', $order, $form, $form_state);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function review(OrderInterface $order) {
-    return $this->pluginDefinition['callback']('review', $order, NULL);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function settingsForm() {
-    $null = NULL;
-    return $this->pluginDefinition['callback']('settings', $null, array());
-  }
-
-}
diff --git a/uc_cart/uc_cart.api.php b/uc_cart/uc_cart.api.php
index cf6315d..6e3f45d 100644
--- a/uc_cart/uc_cart.api.php
+++ b/uc_cart/uc_cart.api.php
@@ -236,129 +236,13 @@ function hook_uc_cart_checkout_start($order) {
 }
 
 /**
- * Registers callbacks for a checkout pane.
+ * Alters checkout pane plugin definitions.
  *
- * The checkout screen for Ubercart is a compilation of enabled checkout panes.
- * A checkout pane can be used to display order information, collect data from
- * the customer, or interact with other panes. Panes are defined in enabled
- * modules with hook_uc_checkout_pane() and displayed and processed through
- * specified callback functions. Some of the settings for each pane are
- * configurable from the checkout settings page with defaults being specified
- * in the hooks.
- *
- * The default panes are defined in uc_cart.module in the function
- * uc_cart_checkout_pane(). These include panes to display the contents of the
- * shopping cart and to collect essential site user information, a shipping
- * address, a payment address, and order comments. Other included modules offer
- * panes for shipping and payment purposes as well.
- *
- * @return
- *   An array of checkout pane arrays, keyed by the internal ID of the pane,
- *   each with the following members:
- *   - title:
- *     - type: string
- *     - value: The name of the pane as it appears on the checkout form.
- *   - callback:
- *     - type: string
- *     - value: The name of the callback function for this pane.
- *   - weight:
- *     - type: integer
- *     - value: Default weight of the pane, defining its order on the checkout
- *       form.
- *   - enabled:
- *     - type: boolean
- *     - value: Optional. Whether or not the pane is enabled by default.
- *       Defaults to TRUE.
- *   - shippable:
- *     - type: boolean
- *     - value: Optional. If TRUE, the pane is only shown if the cart is
- *       shippable. Defaults to NULL.
- *
- * @see http://www.ubercart.org/docs/developer/245/checkout
- */
-function hook_uc_checkout_pane() {
-  $panes['cart'] = array(
-    'callback' => 'uc_checkout_pane_cart',
-    'title' => t('Cart contents'),
-    'weight' => 1,
-  );
-  return $panes;
-}
-
-/**
- * Builds and proceses a pane defined by hook_uc_checkout_pane().
- *
- * @param $op
- *   The operation the pane is performing. Possible values are "view",
- *   "process", "review", and "settings".
- * @param $order
- *   The order being viewed or edited.
- * @param $form
- *   The order's edit form. NULL for non-edit ops.
- * @param &$form_state
- *   The form state array of the edit form. NULL for non-edit ops.
- *
- * @return
- *   Varies according to the value of $op:
- *   - view: An array with two keys, "contents" and an optional "description".
- *     "contents" is a form array to collect the checkout data for the pane. The
- *     description provides help text for the pane as a whole.
- *   - process: A boolean indicating that checkout should continue. During this
- *     op, $order should be modified with the values in
- *     $form_state['values']['panes'][PANE_ID].
- *   - review: An array containing review sections. A review section contains
- *     "title" and "data" keys which have HTML to be displayed on the checkout
- *     review page.
- *   - settings: A settings form which can be used with system_settings_form().
- */
-function uc_checkout_pane_callback($op, $order, $form = NULL, &$form_state = NULL) {
-  // uc_checkout_pane_comments()
-  switch ($op) {
-    case 'view':
-      $description = t('Use this area for special instructions or questions regarding your order.');
-
-      if ($order->id()) {
-        $default = db_query("SELECT message FROM {uc_order_comments} WHERE order_id = :id", array(':id' => $order->id()))->fetchField();
-      }
-      else {
-        $default = NULL;
-      }
-      $contents['comments'] = array(
-        '#type' => 'textarea',
-        '#title' => t('Order comments'),
-        '#default_value' => $default,
-      );
-
-      return array('description' => $description, 'contents' => $contents);
-
-    case 'process':
-      if ($form_state['values']['panes']['comments']['comments']) {
-        db_delete('uc_order_comments')
-          ->condition('order_id', $order->id())
-          ->execute();
-        uc_order_comment_save($order->id(), 0, $form_state['values']['panes']['comments']['comments'], 'order', uc_order_state_default('post_checkout'), TRUE);
-      }
-      return TRUE;
-
-    case 'review':
-      $review = NULL;
-      $result = db_query("SELECT message FROM {uc_order_comments} WHERE order_id = :id", array(':id' => $order->id()));
-      if ($comment = $result->fetchObject()) {
-        $review[] = array('title' => t('Comment'), 'data' => SafeMarkup::checkPlain($comment->message));
-      }
-      return $review;
-  }
-}
-
-/**
- * Alters checkout pane definitions.
- *
- * @param $panes
- *   Array with the panes information as defined in hook_uc_checkout_pane(),
- *   passed by reference.
+ * @param array[] $panes
+ *   Keys are plugin IDs. Values are plugin definitions.
  */
-function hook_uc_checkout_pane_alter(&$panes) {
-  $panes['cart']['callback'] = 'my_custom_module_callback';
+function hook_uc_checkout_pane_alter(array &$panes) {
+  $panes['cart']['title'] = 'Your shopping cart';
 }
 
 /**
