diff --git a/serial.inc b/serial.inc
index 28e12a3..147747c 100644
--- a/serial.inc
+++ b/serial.inc
@@ -41,14 +41,14 @@ function _serial_drop_table(array $field, array $instance) {
 }
 
 /**
- * Renames serial table(s) when a content type us renamed.
+ * Renames serial table(s) when a entity bundle us renamed.
  *
- * @param string $old_type
- *   An old node type machine name.
- * @param string $new_type
- *   A new node type machine name.
+ * @param $bundle_old
+ *   An old entity bundle machine name
+ * @param $bundle_new
+ *   A new entity bundle machine name
  */
-function _serial_rename_tables($old_type, $new_type) {
+function _serial_rename_tables($entity_type, $bundle_old, $bundle_new) {
   // Build the query to find all affected tables.
   $query = db_select('field_config', 'f')
     ->fields('f', array('field_name'));
@@ -56,14 +56,17 @@ function _serial_rename_tables($old_type, $new_type) {
   $query->join(
     'field_config_instance',
     'i',
-    "f.field_name = i.field_name AND f.type = 'serial' AND i.bundle = '$new_type'"
+    "(f.field_name = i.field_name)"
   );
+  $query->condition('f.type', 'serial');
+  $query->condition('i.entity_type', $entity_type);
+  $query->condition('i.bundle', $bundle_new);
 
   // Rename each affected table.
   foreach ($query->addTag('node_access')->execute() as $record) {
     db_rename_table(
-      _serial_get_table_name($old_type, $record->field_name),
-      _serial_get_table_name($new_type, $record->field_name)
+      _serial_get_table_name($entity_type, $bundle_old, $record->field_name),
+      _serial_get_table_name($entity_type, $bundle_new, $record->field_name)
     );
   }
 }
@@ -80,22 +83,24 @@ function _serial_rename_tables($old_type, $new_type) {
  *   The name of the assistant table of the specified field instance.
  */
 function _serial_get_field_table_name(array $field, array $instance) {
-  return _serial_get_table_name($instance['bundle'], $field['field_name']);
+  return _serial_get_table_name($instance['entity_type'], $instance['bundle'], $field['field_name']);
 }
 
 /**
  * Gets the name of the assistant table for a specific field.
  *
+ * @param $entity_type
+ *   Type of entity (e.g. node)
  * @param string $bundle
- *   The name of the entity type that contains the field.
+ *   The name of the entity type that contains the field (e.g. content type)
  * @param string $field_name
  *   The name of the field.
  *
  * @return string
- *   the name of the assistant table of the specified field.
+ *   The name of the assistant table of the specified field.
  */
-function _serial_get_table_name($bundle, $field_name) {
-  return db_escape_table('serial_' . $bundle . '_' . $field_name);
+function _serial_get_table_name($entity_type, $bundle, $field_name) {
+  return db_escape_table('serial_' . $entity_type . '_' . $bundle . '_' . $field_name);
 }
 
 /**
@@ -128,8 +133,10 @@ function _serial_get_table_schema() {
 }
 
 /**
- * Generates a unique serial value (unique per node type).
+ * Generates a unique serial value (unique per entity bundle).
  *
+ * @param $entity_type
+ *   Type of entity (e.g. node)
  * @param string $bundle
  *   Containing bundle (e.g. content type).
  * @param string $field_name
@@ -140,9 +147,9 @@ function _serial_get_table_schema() {
  * @return int
  *   the unique serial value number.
  */
-function _serial_generate_value($bundle, $field_name, $delete = TRUE) {
+function _serial_generate_value($entity_type, $bundle, $field_name, $delete = TRUE) {
   // Get the name of the relevant table.
-  $table = _serial_get_table_name($bundle, $field_name);
+  $table = _serial_get_table_name($entity_type, $bundle, $field_name);
 
   // Insert a temporary record to get a new unique serial value.
   $uniqid = uniqid('', TRUE);
@@ -165,49 +172,70 @@ function _serial_generate_value($bundle, $field_name, $delete = TRUE) {
 }
 
 /**
- * Initializes the value of a new serial field in existing nodes.
+ * Initializes the value of a new serial field in existing entities.
  *
  * @todo Currently works only for nodes - should support comments and users.
  *
+ * @param $entity_type
+ *   Type of entity (e.g. node)
  * @param string $bundle
  *   Containing bundle (e.g. content type).
  * @param string $field_name
  *   The field name.
  *
  * @return int
- *   Number of existing nodes that have been initialized.
+ *   Number of existing entities that have been initialized.
  */
-function _serial_init_old_nodes($bundle, $field_name) {
-  $nodes = node_load_multiple(array(), array('type' => $bundle));
-
-  // Allocate a serial number for every old node.
-  foreach ($nodes as $node) {
-    $node->{$field_name} = array(
-      LANGUAGE_NONE => array(
-        array(
-          'value' => _serial_generate_value($bundle, $field_name, FALSE),
-        ),
-      ),
-    );
-
-    node_save($node);
+function _serial_init_old_entities($entity_type, $bundle, $field_name) {
+  // Prepare meta data.
+  $entity_info = entity_get_info($entity_type);
+  $base_table = $entity_info['base table'];
+  $bundle_key = $entity_info['entity keys']['bundle'];
+  $id_key = $entity_info['entity keys']['id'];
+
+  // @todo - What if $base_table or $id_key is empty?
+
+  // Build the query.
+  $query = "SELECT $id_key FROM {$base_table} ";
+  if (!empty($bundle_key)) {
+    // Some entity types (e.g. user) do not have bundle.
+    $query .= "WHERE $bundle_key = :type ";
+  }
+  $query .= "ORDER BY $id_key";
+
+  // Execute the query.
+  // @todo - Which is better: EntityFieldQuery or db_query?
+  $results = db_query($query, array('type' => $bundle));
+
+  // Allocate a serial number for every old entity:
+  $count = 0;
+  foreach ($results as $result) {
+    $id = $result->{$id_key};
+    if ($id > 0) {
+      // Check for valid id. Prevent anonymous user from being updated.
+      $entity = entity_load($entity_type, array($id));
+      $sid = _serial_generate_value($entity_type, $bundle, $field_name, FALSE);
+      $entity->{$field_name} = array('und' => array(array('value' => $sid)));
+      entity_save($entity_type, $entity);
+      $count++;
+    }
   }
 
-  // Return the number of existing nodes that have been initialized.
-  return count($nodes);
+  // Return the number of existing entities that have been initialized.
+  return $count;
 }
 
 /**
  * Retrieves all the managed serial fields.
  *
  * @return array
- *   Pairs of node type name, field name.
+ *   Result set containing entity type, entity bundle, field name.
  */
 function _serial_get_all_fields() {
   $query = db_select('field_config', 'f');
   $query->join('field_config_instance', 'i', 'i.field_name = f.field_name');
 
-  return $query->fields('i', array('bundle', 'field_name'))
+  return $query->fields('i', array('entity_type', 'bundle', 'field_name'))
     ->condition('f.type', 'serial')
     ->condition('i.deleted', 0)
     ->execute()
diff --git a/serial.install b/serial.install
index e3abdcf..059ebce 100644
--- a/serial.install
+++ b/serial.install
@@ -37,7 +37,7 @@ function serial_schema() {
   $schema = array();
 
   foreach (_serial_get_all_fields() as $field) {
-    $schema[_serial_get_table_name($field->bundle, $field->field_name)] = $table_schema;
+    $schema[_serial_get_table_name($field->entity_type, $field->bundle, $field->field_name)] = $table_schema;
   }
 
   // Return the schema of all the assistant tables (one per field instance).
@@ -57,7 +57,7 @@ function serial_update_7130() {
   // Update the schema of old assistant tables.
   foreach (_serial_get_all_fields() as $field) {
     // Empty the table.
-    $table = _serial_get_table_name($field->bundle, $field->field_name);
+    $table = _serial_get_table_name($field->entity_type, $field->bundle, $field->field_name);
     db_delete($table)->execute();
 
     // Drop nid field and key.
@@ -69,3 +69,16 @@ function serial_update_7130() {
     db_add_unique_key($table, 'uniqid', array('uniqid'));
   }
 }
+
+/**
+ * Add 'node_' to all serial tables.
+ *
+ * Change from serial_{content type}_{field name} to serial_node_{content type}_{field name}
+ */
+function serial_update_7131() {
+  // All old serial tables are of 'node' entity type.
+  foreach (db_find_tables('serial_%') as $tablename) {
+    $tablename_add_node = preg_replace('/^serial_/', 'serial_node_', $tablename);
+    db_rename_table($tablename, $tablename_add_node);
+  }
+}
diff --git a/serial.module b/serial.module
index 9567fab..2e766cd 100644
--- a/serial.module
+++ b/serial.module
@@ -33,10 +33,10 @@ function serial_field_create_instance($instance) {
     _serial_create_table($field, $instance);
 
     // Set serial values for old objects.
-    $old_count = _serial_init_old_nodes($instance['bundle'], $field['field_name']);
+    $old_count = _serial_init_old_entities($instance['entity_type'], $instance['bundle'], $field['field_name']);
 
     if ($old_count > 0) {
-      drupal_set_message(t('Serial values have been automatically set for %count existing nodes.', array(
+      drupal_set_message(t('Serial values have been automatically set for %count existing entities.', array(
         '%count' => $old_count,
       )));
     }
@@ -76,7 +76,7 @@ function serial_field_presave($entity_type, $entity, $field, $instance, $langcod
   if (empty($items)) {
     module_load_include('inc', 'serial');
 
-    $items = array(array('value' => _serial_generate_value($instance['bundle'], $field['field_name'])));
+    $items = array(array('value' => _serial_generate_value($entity_type, $instance['bundle'], $field['field_name'])));
   }
 }
 
@@ -100,13 +100,12 @@ function serial_node_presave($node) {
 }
 
 /**
- * Implements hook_node_type_update().
+ * Implements hook_field_attach_rename_bundle().
  */
-function serial_node_type_update($info) {
-  // Handle content type rename:
-  if (isset($info->old_type) && ($info->old_type != $info->type)) {
+function serial_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
+  if ($bundle_old !== $bundle_new) {
     module_load_include('inc', 'serial');
-    _serial_rename_tables($info->old_type, $info->type);
+    _serial_rename_tables($entity_type, $bundle_old, $bundle_new);
   }
 }
 
@@ -184,3 +183,57 @@ function serial_field_widget(&$form, &$form_state, $field, $instance, $items, $d
     ),
   );
 }
+
+/**
+ * Implements hook_tokens().
+ *
+ * Replace token for generic entity type.
+ */
+function serial_tokens($type, $tokens, $data, $options) {
+  $replacements = array();
+  $sanitize = !empty($options['sanitize']);
+
+  $entity_info = entity_get_info($type);
+  // Make sure type is entity type.
+  if (empty($entity_info)) {
+    return $replacements;
+  }
+
+  $entity_type = $type;
+  if (!empty($data[$entity_type])) {
+    // Generic entity.
+    $entity = $data[$entity_type];
+    foreach ($tokens as $name => $original) {
+      // Convert token to field name.
+      $field_name = str_replace('-', '_', $name);
+      $field_info = field_info_field($field_name);
+      if ($field_info['type'] == 'serial') {
+        // Check if field is used in a pathauto pattern. If so, skip token replacement.
+        $pathauto_match = FALSE;
+        if (module_exists('pathauto')) {
+          $pattern = pathauto_pattern_load_by_entity($entity_type, $data[$entity_type]->type);
+          $path_items = explode('/', $pattern);
+          foreach ($path_items as $path_item) {
+            if (preg_match('/^\[(.*):field_(.*)\]$/', $path_item, $matches)) {
+              if ($field_name == 'field_' . $matches[2]) {
+                $pathauto_match = TRUE;
+                break;
+              }
+            }
+          }
+        }
+        if (!$pathauto_match) {
+          $items = field_get_items($entity_type, $entity, $field_name);
+          if (empty($items)) {
+            continue;
+          }
+          $item = reset($items);
+          $serial_value = $item['value'];
+          $replacements[$original] = $sanitize ? filter_xss($serial_value) : $serial_value;
+        }
+      }
+    }
+  }
+
+  return $replacements;
+}
