diff --git a/uc_product/uc_product.admin.inc b/uc_product/uc_product.admin.inc
index e64303d..9b4768d 100644
--- a/uc_product/uc_product.admin.inc
+++ b/uc_product/uc_product.admin.inc
@@ -40,14 +40,14 @@ function uc_product_administration() {
  * Display a list of product classes.
  */
 function uc_product_class_default() {
-  $result = db_query("SELECT * FROM {uc_product_classes}");
+  $classes = uc_product_class_load();
   $header = array(t('Class ID'), t('Name'), t('Description'), t('Operations'));
   $rows = array();
-  while ($class = db_fetch_object($result)) {
-    $ops = array(
-      l(t('edit'), 'admin/store/products/classes/'. $class->pcid .'/edit'),
-      l(t('delete'), 'admin/store/products/classes/'. $class->pcid .'/delete'),
-    );
+  foreach ($classes as $class) {
+    $ops = array(l(t('edit'), 'admin/store/products/classes/'. $class->pcid .'/edit'));
+    if (empty($class->locked)) {
+      $ops[] = l(t('delete'), 'admin/store/products/classes/'. $class->pcid .'/delete');
+    }
     $rows[] = array(
       $class->pcid,
       $class->name,
@@ -621,6 +621,7 @@ function uc_product_class_form_submit($form, &$form_state) {
   }
   else {
     db_query("UPDATE {uc_product_classes} SET name = '%s', description = '%s' WHERE pcid = '%s'", $form_state['values']['name'], $form_state['values']['description'], $pcid);
+    db_query("UPDATE {node_type} SET name = '%s', description = '%s' WHERE type = '%s'", $form_state['values']['name'], $form_state['values']['description'], $pcid);
     uc_product_node_info(TRUE);
 
     module_invoke_all('product_class', $pcid, 'update');
@@ -636,6 +637,20 @@ function uc_product_class_form_submit($form, &$form_state) {
 }
 
 /**
+ * Check access and get a confirm form for deletion of a product class.
+ *
+ * @see uc_product_class_delete_confirm()
+ */
+function uc_product_class_delete_page($class) {
+  if ($class->locked) {
+    drupal_access_denied();
+  }
+  else {
+    return drupal_get_form('uc_product_class_delete_confirm', $class);
+  }
+}
+
+/**
  * Confirm the deletion of a product class.
  *
  * @see uc_product_class_delete_confirm_submit()
diff --git a/uc_product/uc_product.features.inc b/uc_product/uc_product.features.inc
new file mode 100644
index 0000000..f0adae3
--- /dev/null
+++ b/uc_product/uc_product.features.inc
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * @file
+ * Features integration for Ubercart product classes.
+ */
+
+/**
+ * Implementation of hook_features_export_options().
+ */
+function uc_product_classes_features_export_options() {
+  return uc_product_type_names();
+}
+
+/**
+ * Implementation of hook_features_export().
+ */
+function uc_product_classes_features_export($data, &$export, $module_name = 'uc_product') {
+  // Export node type entries from {uc_product_classes}.
+  ctools_component_features_export('uc_product_classes', $data, $export, $module_name);
+
+  // Next, run the node type exporter to grab CCK fields and variables.
+  return array('node' => $data);
+}
+
+/**
+ * Implementation of hook_features_export_render().
+ */
+function uc_product_classes_features_export_render($module, $data, $export = NULL) {
+  $output = array();
+  $output[] = '  $classes = array(';
+  foreach ($data as $class) {
+    if ($info = uc_product_class_load($class)) {
+      $output[] = "    '{$class}' => array(";
+      foreach (array('name', 'description') as $key) {
+        $text = str_replace("'", "\'", $info->$key);
+        $text = !empty($text) ? "t('{$text}')" : "''";
+        $output[] = "      '{$key}' => {$text},";
+      }
+      $output[] = "    ),";
+    }
+  }
+  $output[] = '  );';
+  $output[] = '  return $classes;';
+  $output = implode("\n", $output);
+  return array('uc_product_default_classes' => $output);
+
+  $output = node_features_export_render($module, $data, $export);
+  return array('uc_product_default_classes' => $output['node_info']);
+}
+
+/**
+ * Implementation of hook_features_revert().
+ */
+function uc_product_classes_features_revert($module) {
+  if ($classes = features_get_default('uc_product_classes', $module)) {
+    foreach ($classes as $pcid => $info) {
+      db_query("UPDATE {uc_product_classes} SET name = '%s', description = '%s' WHERE pcid = '%s'", $info['name'], $info['description'], $pcid);
+      db_query("UPDATE {node_type} SET name = '%s', description = '%s' WHERE type = '%s'", $info['name'], $info['description'], $pcid);
+    }
+  }
+}
diff --git a/uc_product/uc_product.install b/uc_product/uc_product.install
index a0216ad..e31d28f 100644
--- a/uc_product/uc_product.install
+++ b/uc_product/uc_product.install
@@ -13,6 +13,19 @@ function uc_product_schema() {
 
   $schema['uc_product_classes'] = array(
     'description' => 'The list of product node types.',
+    'export' => array(
+      'key' => 'pcid',
+      'key name' => 'Ubercart product class machine name',
+      'primary key' => 'pcid',
+      'identifier' => 'uc_product_class',
+      'default_hook' => 'uc_product_default_classes',
+      'api' => array(
+        'owner' => 'uc_product',
+        'api' => 'uc_product_classes',
+        'minimum_version' => 1,
+        'current_version' => 1,
+      ),
+    ),
     'fields' => array(
       'pcid' => array(
         'description' => 'The node type identifier.',
diff --git a/uc_product/uc_product.module b/uc_product/uc_product.module
index a06fb5c..6fad418 100644
--- a/uc_product/uc_product.module
+++ b/uc_product/uc_product.module
@@ -137,8 +137,8 @@ function uc_product_menu() {
   );
   $items['admin/store/products/classes/%uc_product_class/delete'] = array(
     'access arguments' => array('administer product classes'),
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('uc_product_class_delete_confirm', 4),
+    'page callback' => 'uc_product_class_delete_page',
+    'page arguments' => array(4),
     'type' => MENU_CALLBACK,
     'file' => 'uc_product.admin.inc',
   );
@@ -331,27 +331,23 @@ function uc_product_theme() {
  */
 function uc_product_node_info($reset = FALSE) {
   static $types = array();
-  $title_label = t('Name');
-  $body_label = t('Description');
-
   if (empty($types) || $reset) {
     $types = array();
     $types['product'] = array(
       'name' => t('Product'),
       'module' => 'uc_product',
       'description' => t('This node displays the representation of a product for sale on the website. It includes all the unique information that can be attributed to a specific model number.'),
-      'title_label' => $title_label,
-      'body_label' => $body_label,
+      'title_label' => t('Name'),
+      'body_label' => t('Description'),
     );
 
-    $result = db_query("SELECT pcid, name, description FROM {uc_product_classes}");
-    while ($class = db_fetch_object($result)) {
-      $types[$class->pcid] = array(
-        'name' => $class->name,
-        'module' => 'uc_product',
-        'description' => $class->description,
-        'title_label' => $title_label,
-        'body_label' => $body_label,
+    $classes = uc_product_class_load(NULL, $reset);
+    foreach ($classes as $class) {
+      $class = (array) $class;
+      $class['module'] = 'uc_product';
+      $types[$class['pcid']] = $class + array(
+        'title_label' => t('Name'),
+        'body_label' => t('Description'),
       );
     }
   }
@@ -359,6 +355,20 @@ function uc_product_node_info($reset = FALSE) {
 }
 
 /**
+ * Implementation of hook_node_type().
+ *
+ * Ensure product class names and descriptions are synchronised if the
+ * content type is updated.
+ */
+function uc_product_node_type($op, $type) {
+  switch ($op) {
+    case 'update':
+      db_query("UPDATE {uc_product_classes} SET name = '%s', description = '%s' WHERE pcid = '%s'", $type->name, $type->description, $type->type);
+      break;
+  }
+}
+
+/**
  * Implementation of hook_forms().
  *
  * Register an "add to cart" form for each product to prevent id collisions.
@@ -1889,18 +1899,37 @@ function uc_product_get_description($product) {
 }
 
 /**
- * Load a product class.
+ * Load a product class, or all classes.
  */
-function uc_product_class_load($class_id) {
-  static $classes = array();
+function uc_product_class_load($class_id = NULL, $reset = TRUE) {
+  static $classes;
 
-  if (empty($classes[$class_id])) {
-    $result = db_query("SELECT * FROM {uc_product_classes} WHERE pcid = '%s'", $class_id);
-    $class = db_fetch_object($result);
-    $classes[$class_id] = $class;
+  if ($reset || !isset($classes)) {
+    // Load classes from database.
+    $classes = array();
+    $result = db_query("SELECT * FROM {uc_product_classes}");
+    while ($class = db_fetch_object($result)) {
+      $classes[$class->pcid] = $class;
+    }
+
+    // Merge any module-defined classes.
+    foreach (module_invoke_all('uc_product_default_classes') as $pcid => $class) {
+      if (!isset($classes[$pcid])) {
+        $class += array(
+          'pcid' => $pcid,
+          'name' => $pcid,
+          'description' => '',
+        );
+        drupal_write_record('uc_product_classes', $class);
+        $classes[$pcid] = (object) $class;
+      }
+
+      // Module-defined classes cannot be deleted.
+      $classes[$pcid]->locked = TRUE;
+    }
   }
 
-  return $classes[$class_id];
+  return is_null($class_id) ? $classes : $classes[$class_id];
 }
 
 /**
@@ -2223,3 +2252,17 @@ function uc_product_views_api() {
     'path' => drupal_get_path('module', 'uc_product') .'/views',
   );
 }
+
+/**
+ * Implementation of hook_features_api().
+ */
+function uc_product_features_api() {
+  return array(
+    'uc_product_classes' => array(
+      'name' => t('Ubercart product classes'),
+      'feature_source' => TRUE,
+      'default_hook' => 'uc_product_default_classes',
+      'file' => drupal_get_path('module', 'uc_product') .'/uc_product.features.inc',
+    ),
+  );
+}
