diff --git a/modules/comment/comment.module b/modules/comment/comment.module
index 56fe0982c99e800b7d62921f0dcfd17fb3ee2181..6fdb9867e7cdacce7a7fcb936e813ce73e196a24 100644
--- a/modules/comment/comment.module
+++ b/modules/comment/comment.module
@@ -1312,15 +1312,17 @@ function comment_user_cancel($edit, $account, $method) {
         ->condition('last_comment_uid', $account->uid)
         ->execute();
       break;
-
-    case 'user_cancel_delete':
-      module_load_include('inc', 'comment', 'comment.admin');
-      $cids = db_query('SELECT c.cid FROM {comment} c WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
-      comment_delete_multiple($cids);
-      break;
   }
 }
 
+/**
+ * Implements hook_user_delete().
+ */
+function comment_user_delete($account) {
+  $cids = db_query('SELECT c.cid FROM {comment} c WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
+  comment_delete_multiple($cids);
+}
+
 /**
  * This is *not* a hook_access() implementation. This function is called
  * to determine whether the current user has access to a particular comment.
diff --git a/modules/node/node.module b/modules/node/node.module
index 6d5cdc85ed2e39ee6ec628118d7d0dbdfa465c87..60cff49a8c21a165057bc9dea11d5fc63ecad14e 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -1671,27 +1671,30 @@ function node_user_cancel($edit, $account, $method) {
         ->condition('uid', $account->uid)
         ->execute();
       break;
+  }
+}
 
-    case 'user_cancel_delete':
-      // Delete nodes (current revisions).
-      // @todo Introduce node_mass_delete() or make node_mass_update() more flexible.
-      $nodes = db_select('node', 'n')
-        ->fields('n', array('nid'))
-        ->condition('uid', $account->uid)
-        ->execute()
-        ->fetchCol();
-      node_delete_multiple($nodes);
-      // Delete old revisions.
-      $revisions = db_query('SELECT vid FROM {node_revision} WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
-      foreach ($revisions as $revision) {
-        node_revision_delete($revision);
-      }
-      // Clean history.
-      db_delete('history')
-        ->condition('uid', $account->uid)
-          ->execute();
-      break;
+/**
+ * Implements hook_user_delete().
+ */
+function node_user_delete($account) {
+  // Delete nodes (current revisions).
+  // @todo Introduce node_mass_delete() or make node_mass_update() more flexible.
+  $nodes = db_select('node', 'n')
+    ->fields('n', array('nid'))
+    ->condition('uid', $account->uid)
+    ->execute()
+    ->fetchCol();
+  node_delete_multiple($nodes);
+  // Delete old revisions.
+  $revisions = db_query('SELECT vid FROM {node_revision} WHERE uid = :uid', array(':uid' => $account->uid))->fetchCol();
+  foreach ($revisions as $revision) {
+    node_revision_delete($revision);
   }
+  // Clean history.
+  db_delete('history')
+    ->condition('uid', $account->uid)
+    ->execute();
 }
 
 /**
diff --git a/modules/poll/poll.module b/modules/poll/poll.module
index 88564424c10c67b0bb99073796e5120ed9487b74..f056d7237a0c14f56c8ba6397c2f5157aa9a0747 100644
--- a/modules/poll/poll.module
+++ b/modules/poll/poll.module
@@ -923,15 +923,18 @@ function poll_user_cancel($edit, $account, $method) {
         ->condition('uid', $account->uid)
         ->execute();
       break;
-
-    case 'user_cancel_delete':
-      db_delete('poll_vote')
-        ->condition('uid', $account->uid)
-        ->execute();
-      break;
   }
 }
 
+/**
+ * Implements hook_user_delete().
+ */
+function poll_user_delete($account) {
+  db_delete('poll_vote')
+    ->condition('uid', $account->uid)
+    ->execute();
+}
+
 /**
  * Implements hook_rdf_mapping().
  */
diff --git a/modules/profile/profile.module b/modules/profile/profile.module
index 39101fd6d666acf2a9be66a2d083ceafe4dcb85c..d55c0572c135676083127f6cffeffb8e08ccb267 100644
--- a/modules/profile/profile.module
+++ b/modules/profile/profile.module
@@ -233,14 +233,21 @@ function profile_user_insert(&$edit, $account, $category) {
 function profile_user_cancel(&$edit, $account, $method) {
   switch ($method) {
     case 'user_cancel_reassign':
-    case 'user_cancel_delete':
       db_delete('profile_value')
         ->condition('uid', $account->uid)
         ->execute();
-      break;
   }
 }
 
+/**
+ * Implements hook_user_delete().
+ */
+function profile_user_delete($account) {
+  db_delete('profile_value')
+    ->condition('uid', $account->uid)
+    ->execute();
+}
+
 /**
  * Implements hook_user_load().
  */
@@ -621,4 +628,3 @@ function _profile_get_fields($category, $register = FALSE) {
     ->orderBy('weight', 'ASC')
     ->execute();
 }
-
diff --git a/modules/statistics/statistics.module b/modules/statistics/statistics.module
index d2d0a9738121b0cae7327ce5dc7129c04114c770..be3802fd3dd7bd9c305348878b07b97878661bd5 100644
--- a/modules/statistics/statistics.module
+++ b/modules/statistics/statistics.module
@@ -208,15 +208,18 @@ function statistics_user_cancel($edit, $account, $method) {
         ->condition('uid', $account->uid)
         ->execute();
       break;
-
-    case 'user_cancel_delete':
-      db_delete('accesslog')
-        ->condition('uid', $account->uid)
-        ->execute();
-      break;
   }
 }
 
+/**
+ * Implements hook_user_delete().
+ */
+function statistics_user_delete($account) {
+  db_delete('accesslog')
+    ->condition('uid', $account->uid)
+    ->execute();
+}
+
 /**
  * Implements hook_cron().
  */
diff --git a/modules/trigger/trigger.module b/modules/trigger/trigger.module
index 2bdfec24d0a89c4696dc3f5e31499730ecec5693..db017a24aa4e7c3c2236209096a01b061c130781 100644
--- a/modules/trigger/trigger.module
+++ b/modules/trigger/trigger.module
@@ -514,12 +514,18 @@ function trigger_user_update(&$edit, $account, $category) {
 function trigger_user_cancel($edit, $account, $method) {
   switch ($method) {
     case 'user_cancel_reassign':
-    case 'user_cancel_delete':
       _trigger_user('user_delete', $edit, $account, $method);
       break;
   }
 }
 
+/**
+ * Implements hook_user_delete().
+ */
+function trigger_user_delete($account) {
+  _trigger_user('user_delete', $edit, $account, $method);
+}
+
 /**
  * Implements hook_user_view().
  */
@@ -618,4 +624,3 @@ function _trigger_get_all_info() {
 
   return $triggers;
 }
-
diff --git a/modules/user/user.api.php b/modules/user/user.api.php
index 6f818688d193073da5872b35055c2b224e9eadc7..07f28611cc02754477a23f3365a8b60a1f77b997 100644
--- a/modules/user/user.api.php
+++ b/modules/user/user.api.php
@@ -31,12 +31,30 @@ function hook_user_load($users) {
   }
 }
 
+/**
+ * Respond to user deletion.
+ *
+ * This hook is invoked from user_delete_multiple() after the account has been
+ * removed from the user tables in the database, and before
+ * field_attach_delete() is called.
+ *
+ * @param $account
+ *   The account that is being deleted.
+ *
+ * @see user_delete_multiple()
+ */
+function hook_user_delete($account) {
+  db_delete('mytable')
+    ->condition('uid', $account->uid)
+    ->execute();
+}
+
 /**
  * Act on user account cancellations.
  *
  * The user account is being canceled. Depending on the account cancellation
- * method, the module should either do nothing, unpublish content, anonymize
- * content, or delete content and data belonging to the canceled user account.
+ * method, the module should either do nothing, unpublish content, or anonymize
+ * content.
  *
  * Expensive operations should be added to the global batch with batch_set().
  *
@@ -83,26 +101,6 @@ function hook_user_cancel($edit, $account, $method) {
         ->condition('uid', $account->uid)
         ->execute();
       break;
-
-    case 'user_cancel_delete':
-      // Delete nodes (current revisions).
-      $nodes = db_select('node', 'n')
-        ->fields('n', array('nid'))
-        ->condition('uid', $account->uid)
-        ->execute()
-        ->fetchCol();
-      foreach ($nodes as $nid) {
-        node_delete($nid);
-      }
-      // Delete old revisions.
-      db_delete('node_revision')
-        ->condition('uid', $account->uid)
-        ->execute();
-      // Clean history.
-      db_delete('history')
-        ->condition('uid', $account->uid)
-        ->execute();
-      break;
   }
 }
 
diff --git a/modules/user/user.module b/modules/user/user.module
index 0c17eaa45a94c088ed05bfb2ccdc68769943c5f4..510c9c2615643aa37b5249a890ec1115f7d98523 100644
--- a/modules/user/user.module
+++ b/modules/user/user.module
@@ -2144,8 +2144,11 @@ function user_cancel($edit, $uid, $method) {
   );
   batch_set($batch);
 
-  // Allow modules to add further sets to this batch.
-  module_invoke_all('user_cancel', $edit, $account, $method);
+  // Modules use hook_user_delete() to respond to deletion.
+  if ($method != 'user_cancel_delete') {
+    // Allow modules to add further sets to this batch.
+    module_invoke_all('user_cancel', $edit, $account, $method);
+  }
 
   // Finish the batch and actually cancel the account.
   $batch = array(
@@ -2193,15 +2196,7 @@ function _user_cancel($edit, $account, $method) {
       if (!empty($edit['user_cancel_notify'])) {
         _user_mail_notify('status_canceled', $account);
       }
-      db_delete('users')
-        ->condition('uid', $account->uid)
-        ->execute();
-      db_delete('users_roles')
-        ->condition('uid', $account->uid)
-        ->execute();
-      db_delete('authmap')
-        ->condition('uid', $account->uid)
-        ->execute();
+      user_delete($account->uid);
       drupal_set_message(t('%name has been deleted.', array('%name' => $account->name)));
       watchdog('user', 'Deleted user: %name %email.', array('%name' => $account->name, '%email' => '<' . $account->mail . '>'), WATCHDOG_NOTICE);
       break;
@@ -2220,6 +2215,45 @@ function _user_cancel($edit, $account, $method) {
   cache_clear_all();
 }
 
+/**
+ * Delete a user.
+ *
+ * @param $uid
+ *   A user ID.
+ */
+function user_delete($uid) {
+  user_delete_multiple(array($uid));
+}
+
+/**
+ * Delete multiple user accounts.
+ *
+ * @param $uids
+ *   An array of user IDs.
+ */
+function user_delete_multiple(array $uids) {
+  if (!empty($uids)) {
+    $accounts = user_load_multiple($uids, array());
+
+    foreach ($accounts as $uid => $account) {
+      module_invoke_all('user_delete', $account);
+      field_attach_delete('user', $account);
+    }
+
+    db_delete('users')
+      ->condition('uid', $uids, 'IN')
+      ->execute();
+    db_delete('users_roles')
+      ->condition('uid', $uids, 'IN')
+      ->execute();
+    db_delete('authmap')
+      ->condition('uid', $uids, 'IN')
+      ->execute();
+
+    entity_get_controller('user')->resetCache();
+  }
+}
+
 /**
  * Page callback wrapper for user_view().
  */