diff --git a/file_entity.file_api.inc b/file_entity.file_api.inc
index effd2aa..a5dae12 100644
--- a/file_entity.file_api.inc
+++ b/file_entity.file_api.inc
@@ -461,7 +461,7 @@ function _file_entity_sort_weight_label($a, $b) {
  *   A file object, or FALSE on error.
  *
  * @todo This should probably be named file_load_by_uri($uri, $create_if_not_exists).
- * @todo Remove this function when http://drupal.org/node/685818 is fixed.
+ * @todo Remove this function when http://drupal.org/file/685818 is fixed.
  */
 function file_uri_to_object($uri, $use_existing = TRUE) {
   $file = FALSE;
@@ -487,3 +487,319 @@ function file_uri_to_object($uri, $use_existing = TRUE) {
 
   return $file;
 }
+
+/**
+ * Builds and returns the list of available file types.
+ *
+ * The list of types is built by invoking hook_file_info() on all modules and
+ * comparing this information with the file types in the {file_type} table.
+ * These two information sources are not synchronized during module installation
+ * until file_types_rebuild() is called.
+ *
+ * @param $rebuild
+ *  TRUE to rebuild file types. Equivalent to calling file_types_rebuild().
+ * @return
+ *   Associative array with two components:
+ *   - names: Associative array of the names of file types, keyed by the type.
+ *   - types: Associative array of file type objects, keyed by the type.
+ *   Both of these arrays will include new types that have been defined by
+ *   hook_file_info() implementations but not yet saved in the {file_type}
+ *   table. These are indicated in the type object by $type->is_new being set
+ *   to the value 1. These arrays will also include obsolete types: types that
+ *   were previously defined by modules that have now been disabled, or for
+ *   whatever reason are no longer being defined in hook_file_type_info()
+ *   implementations, but are still in the database. These are indicated in the
+ *   type object by $type->disabled being set to TRUE.
+ */
+function _file_types_build($rebuild = FALSE) {
+  $cid = 'file_types:' . $GLOBALS['language']->language;
+
+  if (!$rebuild) {
+    $_file_types = &drupal_static(__FUNCTION__);
+    if (isset($_file_types)) {
+      return $_file_types;
+    }
+    if ($cache = cache_get($cid)) {
+      $_file_types = $cache->data;
+      return $_file_types;
+    }
+  }
+
+  $_file_types = (object) array('types' => array(), 'names' => array());
+
+  foreach (module_implements('file_type_info') as $module) {
+    $info_array = module_invoke($module, 'file_type_info');
+    foreach ($info_array as $type => $info) {
+      $info['type'] = $type;
+      $_file_types->types[$type] = file_type_set_defaults($info);
+      $_file_types->types[$type]->module = $module;
+      $_file_types->names[$type] = $info['name'];
+    }
+  }
+  $query = db_select('file_type', 'ft')
+    ->addTag('translatable')
+    ->addTag('file_type_access')
+    ->fields('ft')
+    ->orderBy('ft.type', 'ASC');
+  if (!$rebuild) {
+    $query->condition('disabled', 0);
+  }
+  foreach ($query->execute() as $type_object) {
+    $type_object->mimetypes = array();
+    $mimetypes = db_select('file_type_mimetypes', 'ftm')
+      ->addTag('file_type_access')
+      ->fields('ftm', array('mimetype'))
+      ->condition('ftm.type', $type_object->type);
+    foreach ($mimetypes->execute() as $mimetype) {
+      $type_object->mimetypes[] = $mimetype->mimetype;
+    }
+
+    $type_db = $type_object->type;
+    // Original disabled value.
+    $disabled = $type_object->disabled;
+    // Check for file types from disabled modules and mark their types for removal.
+    // Types defined by the file module in the database (rather than by a separate
+    // module using hook_file_type_info) have a base value of 'file_entity'.
+    if ($type_object->base != 'file_entity' && empty($_file_types->types[$type_db])) {
+      $type_object->disabled = TRUE;
+    }
+    if (isset($_file_types->types[$type_db])) {
+      $type_object->disabled = FALSE;
+    }
+    if (!isset($_file_types->types[$type_db]) || $type_object->modified) {
+      $_file_types->types[$type_db] = $type_object;
+      $_file_types->names[$type_db] = $type_object->name;
+
+      if ($type_db != $type_object->orig_type) {
+        unset($_file_types->types[$type_object->orig_type]);
+        unset($_file_types->names[$type_object->orig_type]);
+      }
+    }
+    $_file_types->types[$type_db]->disabled = $type_object->disabled;
+    $_file_types->types[$type_db]->disabled_changed = $disabled != $type_object->disabled;
+  }
+
+  if ($rebuild) {
+    foreach ($_file_types->types as $type => $type_object) {
+      if (!empty($type_object->is_new) || !empty($type_object->disabled_changed)) {
+        file_type_save($type_object);
+      }
+    }
+  }
+
+  asort($_file_types->names);
+
+  cache_set($cid, $_file_types);
+
+  return $_file_types;
+}
+
+/**
+ * Clears the file type cache.
+ */
+function file_type_cache_reset() {
+  cache_clear_all('file_types:', 'cache', TRUE);
+  drupal_static_reset('_file_types_build');
+}
+
+/**
+ * Sets the default values for a file type.
+ *
+ * The defaults are appropriate for a type defined through hook_file_type_info(),
+ * since 'custom' is TRUE for types defined in the user interface, and FALSE
+ * for types defined by modules. (The 'custom' flag prevents types from being
+ * deleted through the user interface.) Also, the default for 'locked' is TRUE,
+ * which prevents users from changing the machine name of the type.
+ *
+ * @param $info
+ *   An object or array containing values to override the defaults. See
+ *   hook_file_type_info() for details on what the array elements mean.
+ *
+ * @return
+ *   A file type object, with missing values in $info set to their defaults.
+ */
+function file_type_set_defaults($info = array()) {
+  $info = (array) $info;
+  $new_type = $info + array(
+    'type' => '',
+    'name' => '',
+    'base' => '',
+    'description' => '',
+    'help' => '',
+    'custom' => 0,
+    'modified' => 0,
+    'locked' => 1,
+    'disabled' => 0,
+    'mimetypes' => array(),
+    'is_new' => 1,
+  );
+  $new_type = (object) $new_type;
+
+  if (empty($new_type->module)) {
+    $new_type->module = $new_type->base == 'file_entity' ? 'file_entity' : '';
+  }
+  $new_type->orig_type = isset($info['type']) ? $info['type'] : '';
+
+  return $new_type;
+}
+
+/**
+ *  Update an existing file type or create a new one.
+ *
+ *  @param $info
+ *  The file type to save, as an object.
+ *    $info is an object with the following fields:
+ *      ->type => The machine name of the file type, such as 'video';
+ *      ->name => The human readable name;
+ *      ->description => A brief description of the file type;
+ *      ->help ;
+ *      ->custom ;
+ *      ->modified ;
+ *      ->locked ;
+ *      ->disabled ;
+ *      ->mimetypes => An array of mimetypes supported by this file type.
+ */
+function file_type_save(&$info) {
+  $info = (object) $info;
+  $existing_type = !empty($info->old_type) ? $info->old_type : $info->type;
+  $is_existing = (bool) db_query_range('SELECT 1 FROM {file_type} WHERE type = :type', 0, 1, array(':type' => $existing_type))->fetchField();
+  $type = file_type_set_defaults($info);
+
+  $fields = array(
+    'type' => (string) $type->type,
+    'name' => (string) $type->name,
+    'base' => (string) $type->base,
+    'description' => (string) $type->description,
+    'help' => (string) $type->help,
+    'custom' => (int) $type->custom,
+    'modified' => (int) $type->modified,
+    'locked' => (int) $type->locked,
+    'disabled' => (int) $type->disabled,
+    'module' => $type->module,
+  );
+
+  if (empty($type->type)) {
+    throw new Exception(t('Unable to add file type, as its machine name is not provided.'));
+  }
+
+  if (!is_array($type->mimetypes)) {
+    throw new Exception(t('File type mimetypes must be an array'));
+  }
+
+  if ($is_existing) {
+    db_update('file_type')
+      ->fields($fields)
+      ->condition('type', $existing_type)
+      ->execute();
+
+    db_delete('file_type_mimetypes')
+    ->condition('type', $type->type)
+    ->execute();
+
+    foreach ($type->mimetypes as $mimetype) {
+      db_insert('file_type_mimetypes')
+        ->fields(array('type' => $type->type, 'mimetype' => $mimetype))
+        ->execute();
+    }
+
+    if (!empty($type->old_type) && $type->old_type != $type->type) {
+      field_attach_rename_bundle('file', $type->old_type, $type->type);
+    }
+
+    module_invoke_all('file_type_update', $type);
+    $status = SAVED_UPDATED;
+  }
+  else {
+    $fields['orig_type'] = (string) $type->orig_type;
+    db_insert('file_type')
+      ->fields($fields)
+      ->execute();
+
+    foreach ($type->mimetypes as $mimetype) {
+      db_insert('file_type_mimetypes')
+        ->fields(array('type' => $type->type, 'mimetype' => $mimetype))
+        ->execute();
+    }
+
+    field_attach_create_bundle('file', $type->type);
+
+    module_invoke_all('file_type_insert', $type);
+    $status = SAVED_NEW;
+  }
+
+  // Clear the file type cache.
+  file_type_cache_reset();
+
+  // Change the reference.
+  $info = $type;
+
+  return $status;
+}
+
+/**
+ * Delete a file type from the database.
+ *
+ * @param $type
+ * The machine-readable name of the file type to be deleted.
+ */
+function file_type_delete($type) {
+  $info = file_type_get_type($type);
+  db_delete('file_type')
+    ->condition('type', $type)
+    ->execute();
+  db_delete('file_type_mimetypes')
+    ->condition('type', $type)
+    ->execute();
+  field_attach_delete_bundle('file', $type);
+  module_invoke_all('file_type_delete', $info);
+
+  // Clear the file type cache.
+  file_type_cache_reset();
+}
+
+/**
+ * Extract the type name.
+ *
+ * @param $file
+ *   Either a string or object, containing the file type information.
+ *
+ * @return
+ *   file type of the passed-in data.
+ */
+function _file_extract_type($file) {
+  return is_object($file) ? $file->type : $file;
+}
+
+/**
+ * Returns a list of all the available file types.
+ *
+ * This list can include types that are queued for addition or deletion.
+ * See _file_types_build() for details.
+ *
+ * @return
+ *   An array of file types, as objects, keyed by the type.
+ *
+ * @see file_type_get_type()
+ */
+function file_type_get_types() {
+  return _file_types_build()->types;
+}
+
+/**
+ * Returns the file type of the passed file or file type string.
+ *
+ * @param $file
+ *   An object or string that indicates the file type to return.
+ *
+ * @return
+ *   A single file type, as an object, or FALSE if the file type is not found.
+ *   The file type is an object containing fields from hook_file_info() return
+ *   values, as well as the field 'type' (the machine-readable type) and other
+ *   fields used internally and defined in _file_types_build(),
+ *   hook_file_info(), and file_type_set_defaults().
+ */
+function file_type_get_type($file) {
+  $type = _file_extract_type($file);
+  $types = _file_types_build()->types;
+  return isset($types[$type]) ? $types[$type] : FALSE;
+}
diff --git a/file_entity.install b/file_entity.install
index 3fe21a2..d13bb0b 100644
--- a/file_entity.install
+++ b/file_entity.install
@@ -23,6 +23,11 @@ function file_entity_schema_alter(&$schema) {
  * Implements hook_schema().
  */
 function file_entity_schema() {
+   // Using this strange looking function name because of http://drupal.org/node/150220.
+  // Any changes to this table should happen after this line.
+  $schema['file_type'] = _file_entity_update_7105_schema_file_type();
+  $schema['file_type_mimetypes'] = _file_entity_update_7105_schema_file_type_mimetypes();
+
   $schema['file_display'] = array(
     'description' => 'Stores configuration options for file displays.',
     'fields' => array(
@@ -120,15 +125,95 @@ function file_entity_install() {
   foreach ($roles as $rid => $role) {
     user_role_grant_permissions($rid, array('view file'));
   }
+
+  _file_entity_install_default_file_types();
 }
 
 /**
  * Implement hook_uninstall().
  */
 function file_entity_uninstall() {
+  foreach (_file_types_build()->names as $type) {
+    file_type_delete($type);
+  }
   db_drop_field('file_managed', 'type');
 }
 
+function _file_entity_install_default_file_types() {
+  // Insert default pre-defined file types into the database. For a complete
+  // list of available file type attributes, refer to the file type API
+  // documentation.
+  $types = array(
+    array(
+      'type' => 'image',
+      'name' => st('Image'),
+      'base' => 'file_entity',
+      'description' => st("An <em>Image</em> is a two-dimensional picture that has a similar appearance to some subject, usually a physical object or a person."),
+      'custom' => 1,
+      'modified' => 1,
+      'locked' => 0,
+      'mimetypes' => array(
+        'image/jpeg',
+        'image/gif',
+        'image/png',
+      ),
+    ),
+    array(
+      'type' => 'video',
+      'name' => st('Video'),
+      'base' => 'file_entity',
+      'description' => st('<em>Videos</em> are a sequence of still images representing scenes in motion.'),
+      'custom' => 1,
+      'modified' => 1,
+      'locked' => 0,
+      'mimetypes' => array(
+        'video/quicktime',
+        'video/mp4',
+        'video/x-msvideo',
+        'video/ogg',
+      ),
+    ),
+    array(
+      'type' => 'audio',
+      'name' => st('Audio'),
+      'base' => 'file_entity',
+      'description' => st('<em>Audio</em> files are an electrical representation of sound.'),
+      'custom' => 1,
+      'modified' => 1,
+      'locked' => 0,
+      'mimetypes' => array(
+        'audio/mpeg',
+        'audio/x-ms-wma',
+        'audio/x-wav',
+        'audio/ogg',
+      ),
+    ),
+    array(
+      'type' => 'document',
+      'name' => st('Document'),
+      'base' => 'file_entity',
+      'description' => st('A <em>Document</em> is a work of writing intended to store and communicate information.'),
+      'custom' => 1,
+      'modified' => 1,
+      'locked' => 0,
+      'mimetypes' => array(
+        'text/plain',
+        'application/msword',
+        'application/vnd.ms-excel',
+        'application/pdf',
+        'application/vnd.ms-powerpoint',
+        'application/vnd.oasis.opendocument.text',
+        'application/vnd.oasis.opendocument.spreadsheet',
+        'application/vnd.oasis.opendocument.presentation',
+      ),
+    ),
+  );
+
+  foreach ($types as $type) {
+    file_type_save($type);
+  }
+}
+
 /**
  * Create the {file_display} database table.
  */
@@ -246,3 +331,132 @@ function file_entity_update_7104() {
     }
   }
 }
+
+// Using this strange looking function name because of http://drupal.org/node/150220.
+// This function should never be modified.
+function _file_entity_update_7105_schema_file_type() {
+  return array(
+    'description' => 'Stores the settings for file types.',
+    'fields' => array(
+      'type' => array(
+        'description' => 'The machine name of the file type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'name' => array(
+        'description' => 'The human readable name of the file type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+        'translatable' => TRUE,
+      ),
+      'description' => array(
+        'description' => 'A brief description of this file type.',
+        'type' => 'text',
+        'not null' => TRUE,
+        'size' => 'medium',
+        'translatable' => TRUE,
+      ),
+      'help' => array(
+        'description' => 'Help information shown to the user when creating a file of this type.',
+        'type' => 'text',
+        'not null' => TRUE,
+        'size' => 'medium',
+        'translatable' => TRUE,
+      ),
+      'module' => array(
+        'description' => 'The module defining this file type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'base' => array(
+        'description' => 'The base string used to construct callbacks corresponding to this file type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'custom' => array(
+        'description' => 'A boolean indicating whether this file type is defined by a module (FALSE) or by a user via Add file type (TRUE).',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'modified' => array(
+        'description' => 'A boolean indicating whether this file type has been modified by an administrator; currently not used in any way.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'locked' => array(
+        'description' => 'A boolean indicating whether the administrator can change the machine name of this file type.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'disabled' => array(
+        'description' => 'A boolean indicating whether the file type is disabled.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'orig_type' => array(
+        'description' => 'The original machine-readable name of this file type. This may be different from the current type name if the locked field is 0.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ),
+    'primary key' => array('type'),
+  );
+}
+
+// Using this strange looking function name because of http://drupal.org/node/150220.
+// This function should never be modified.
+function _file_entity_update_7105_schema_file_type_mimetypes() {
+  return array(
+    'description' => 'Maps mimetypes to file types.',
+    'fields' => array(
+      'type' => array(
+        'description' => 'The machine name of the file type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'mimetype' => array(
+        'description' => 'Mimetypes mapped to this file type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ),
+    'indexes' => array(
+      array('file_type' => 'type'),
+      array('file_type_mimetype' => 'mimetype'),
+    ),
+  );
+}
+
+/**
+ * Add the file_type and file_type_mimetypes tables.
+ */
+function file_entity_update_7105() {
+  db_create_table('file_type', _file_entity_update_7105_schema_file_type());
+  db_create_table('file_type_mimetypes',  _file_entity_update_7105_schema_file_type_mimetypes());
+
+  // The Media module handles updating the file types. However, we might not
+  // have that module installed.
+  if (!module_exists('media')) {
+      _file_entity_install_default_file_types();
+  }
+}
