diff --git a/lib/Drupal/profile2/Profile.php b/lib/Drupal/profile2/Profile.php
index bc8d6c9..8f361ab 100644
--- a/lib/Drupal/profile2/Profile.php
+++ b/lib/Drupal/profile2/Profile.php
@@ -29,13 +29,6 @@ class Profile extends Entity {
   public $type;
 
   /**
-   * The profile label.
-   *
-   * @var string
-   */
-  public $label;
-
-  /**
    * The user id of the profile owner.
    *
    * @var integer
@@ -56,92 +49,45 @@ class Profile extends Entity {
    */
   public $changed;
 
-  public function __construct(array $values = array(), $entity_type) {
-    if (isset($values['user'])) {
-      $this->setUser($values['user']);
-      unset($values['user']);
-    }
-    if (isset($values['type']) && is_object($values['type'])) {
-      $values['type'] = $values['type']->type;
-    }
-    if (!isset($values['label']) && isset($values['type']) && $type = profile2_type_load($values['type'])) {
-      // Initialize the label with the type label, so newly created profiles
-      // have that as interim label.
-      $values['label'] = $type->label;
-    }
-    parent::__construct($values, $entity_type);
-  }
-
   /**
    * Returns the user owning this profile.
+   *
+   * @return Drupal\user\User
+   *   The user owning this profile.
    */
   public function user() {
     return user_load($this->uid);
   }
 
   /**
-   * Sets a new user owning this profile.
+   * Returns the associated profile type.
    *
-   * @param $account
-   *   The user account object or the user account id (uid).
-   */
-  public function setUser($account) {
-    $this->uid = is_object($account) ? $account->uid : $account;
-  }
-
-  /**
-   * Gets the associated profile type object.
-   *
-   * @return ProfileType
+   * @return Drupal\profile2\ProfileType
+   *   The associated profile type object.
    */
   public function type() {
     return profile2_type_load($this->type);
   }
 
   /**
-   * Overwrites EntityInterface::id().
+   * Overrides Drupal\Core\Entity\Entity::id().
    */
   public function id() {
     return isset($this->pid) ? $this->pid : NULL;
   }
 
   /**
-   * Overwrites EntityInterface::bundle().
+   * Overrides Drupal\Core\Entity\Entity::bundle().
    */
   public function bundle() {
     return $this->type;
   }
 
   /**
-   * Returns the full url() for the profile.
-   */
-  public function url() {
-    $uri = $this->uri();
-    return url($uri['path'], $uri);
-  }
-
-  /**
-   * Returns the drupal path to this profile.
+   * Overrides Drupal\Core\Entity\Entity::label().
    */
-  public function path() {
-    $uri = $this->uri();
-    return $uri['path'];
-  }
-
-  public function defaultUri() {
-    return array(
-      'path' => 'user/' . $this->uid,
-      'options' => array('fragment' => 'profile-' . $this->type),
-    );
-  }
-
-  public function defaultLabel() {
-    if (module_exists('profile2_i18n')) {
-      // Run the label through i18n_string() using the profile2_type label
-      // context, so the default label (= the type's label) gets translated.
-      return entity_i18n_string('profile2:profile2_type:' . $this->type . ':label', $this->label);
-    }
-    return $this->label;
+  public function label($langcode = NULL) {
+    return $this->type()->label();
   }
 
 }
diff --git a/lib/Drupal/profile2/ProfileFormController.php b/lib/Drupal/profile2/ProfileFormController.php
index dd765be..5e7dd36 100644
--- a/lib/Drupal/profile2/ProfileFormController.php
+++ b/lib/Drupal/profile2/ProfileFormController.php
@@ -20,10 +20,6 @@ class ProfileFormController extends EntityFormController {
   protected function actionsElement(array $form, array &$form_state) {
     $element = parent::actionsElement($form, $form_state);
 
-    if (!user_access('administer profiles')) {
-      unset($element['delete']);
-    }
-
     return $element;
   }
 
@@ -40,6 +36,17 @@ class ProfileFormController extends EntityFormController {
     else {
       drupal_set_message(t("%name's profile has been updated.", array('%name' => user_format_name(user_load($profile->uid)))));
     }
+
+    $uri = $profile->uri();
+    $form_state['redirect'] = array($uri['path'], $uri['options']);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::delete().
+   */
+  public function delete(array $form, array &$form_state) {
+    $profile = $this->getEntity($form_state);
+    $form_state['redirect'] = 'user/' . $profile->uid . '/edit/' . $profile->bundle() . '/delete';
   }
 
 }
diff --git a/lib/Drupal/profile2/Tests/ProfileCRUDTest.php b/lib/Drupal/profile2/Tests/ProfileCRUDTest.php
index bf29da1..1894b77 100644
--- a/lib/Drupal/profile2/Tests/ProfileCRUDTest.php
+++ b/lib/Drupal/profile2/Tests/ProfileCRUDTest.php
@@ -46,7 +46,7 @@ class ProfileCRUDTest extends WebTestBase {
     ));
     $this->assertIdentical($profile->id(), NULL);
     $this->assertIdentical($profile->type, $expected['type']);
-    $this->assertIdentical($profile->label, $types[0]->label());
+    $this->assertIdentical($profile->label(), $types[0]->label());
     $this->assertIdentical($profile->uid, $this->user1->id());
     $this->assertIdentical($profile->created, REQUEST_TIME);
     $this->assertIdentical($profile->changed, NULL);
diff --git a/profile2.admin.inc b/profile2.admin.inc
index 6cf7111..7fbe835 100644
--- a/profile2.admin.inc
+++ b/profile2.admin.inc
@@ -28,7 +28,7 @@ function profile2_type_add() {
  *   A form array as expected by drupal_render().
  */
 function profile2_type_edit(ProfileType $type) {
-  drupal_set_title(t('Edit %label profile type', array('%label' => $type->label)), PASS_THROUGH);
+  drupal_set_title(t('Edit %label profile type', array('%label' => $type->label())), PASS_THROUGH);
   return entity_get_form($type);
 }
 
diff --git a/profile2.module b/profile2.module
index 52bbcca..3b8ea90 100644
--- a/profile2.module
+++ b/profile2.module
@@ -80,22 +80,15 @@ function profile2_entity_info() {
 
 /**
  * Entity URI callback for profiles.
- *
- * @param Drupal\profile2\Profile $profile
- *   A Profile entity.
  */
 function profile2_profile_uri(Profile $profile) {
-  // @todo Call into user_uri() to ensure consistent URIs?
-  return array(
-    'path' => 'user/' . $profile->uid,
-  );
+  $uri = user_uri(entity_load('user', $profile->uid));
+  $uri['options']['fragment'] = 'profile-' . $profile->bundle();
+  return $uri;
 }
 
 /**
  * Entity URI callback for profile types.
- *
- * @param Drupal\profile2\ProfileType $profile_type
- *   A profile type entity.
  */
 function profile2_profile_type_uri(ProfileType $profile_type) {
   return array(
@@ -162,6 +155,16 @@ function profile2_menu() {
     'page arguments' => array(3),
     'type' => MENU_LOCAL_TASK,
   );
+  $items['user/%user/edit/%profile2_menu/delete'] = array(
+    'load arguments' => array('%map', 'edit'),
+    'title' => 'Delete profile',
+    'access callback' => 'profile2_profile_edit_access',
+    'access arguments' => array(3),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('profile2_delete_confirm_form', 3),
+    'type' => MENU_CALLBACK,
+    'file' => 'profile2.pages.inc',
+  );
   return $items;
 }
 
@@ -214,7 +217,7 @@ function profile2_menu_local_tasks_alter(&$data, $router_item, $root_path) {
       }
     }
     // Expand the dynamic %profile_menu argument into a tab for each type.
-    $types = profile2_get_types();
+    $types = entity_load_multiple('profile2_type');
     foreach ($types as $type) {
       // If the current page is the active tab registered in hook_menu(), then
       // the menu router item with the dynamic argument will be exposed already.
@@ -251,16 +254,10 @@ function profile2_type_list_page() {
 }
 
 /**
- * Menu argument loader; Load a profile type by string.
- *
- * @param string $id
- *   The machine-readable name of a profile type to load.
- *
- * @return Drupal\profile2\ProfileType|false
- *   A profile type array or FALSE if $type does not exist.
+ * Menu callback for loading a profile type.
  */
-function profile2_type_load($id) {
-  return entity_load('profile2_type', $id);
+function profile2_type_load($type) {
+  return entity_load('profile2_type', $type);
 }
 
 /**
@@ -278,7 +275,7 @@ function profile2_permission() {
     ),
   );
   // Generate per profile type permissions.
-  foreach (profile2_get_types() as $type) {
+  foreach (entity_load_multiple('profile2_type') as $type) {
     $type_name = $type->id();
     $permissions += array(
       "edit own $type_name profile" => array(
@@ -299,16 +296,6 @@ function profile2_permission() {
 }
 
 /**
- * Gets an array of all profile types, keyed by the machine name.
- *
- * @return array
- *   An array of profile type objects.
- */
-function profile2_get_types() {
-  return entity_load_multiple('profile2_type');
-}
-
-/**
  * Fetch profiles by account.
  *
  * @param \Drupal\user\User $account
@@ -353,14 +340,14 @@ function profile2_user_predelete($account) {
 /**
  * Implements hook_user_view().
  */
-function profile2_user_view($account, $view_mode, $langcode) {
-  foreach (profile2_get_types() as $id => $type) {
+function profile2_user_view(User $account, $view_mode, $langcode) {
+  foreach (entity_load_multiple('profile2_type') as $id => $type) {
     if ($type->userView && $profile = profile2_load_by_user($account, $id)) {
       if (profile2_access('view', $profile)) {
         $account->content['profile_' . $id] = array(
           '#type' => 'user_profile_category',
-          '#title' => $profile->label,
-          '#prefix' => '<a id="profile-' . $profile->type . '"></a>',
+          '#title' => $profile->label(),
+          '#prefix' => '<a id="profile-' . $profile->bundle() . '"></a>',
         );
         entity_render_controller('profile2')->buildContent(array($profile), 'account');
         $account->content['profile_' . $id]['view'] = $profile->content;
@@ -373,7 +360,7 @@ function profile2_user_view($account, $view_mode, $langcode) {
  * Implements hook_form_FORM_ID_alter() for the registration form.
  */
 function profile2_form_user_register_form_alter(&$form, &$form_state) {
-  foreach (profile2_get_types() as $id => $type) {
+  foreach (entity_load_multiple('profile2_type') as $id => $type) {
     if ($type->get('registration')) {
       if (empty($form_state['profiles'][$id])) {
         $form_state['profiles'][$id] = entity_create('profile2', array('type' => $id));
@@ -639,13 +626,3 @@ function profile2_field_access($op, $field, $entity_type, $profile = NULL, $acco
     }
   }
 }
-
-/**
- * Entity metadata callback to load profiles for the given user account.
- */
-function profile2_user_get_properties($account, array $options, $name) {
-  // Remove the leading 'profile_' from the property name to get the type name.
-  $profile = profile2_load_by_user($account, substr($name, 8));
-  return $profile ? $profile : NULL;
-}
-
diff --git a/profile2.pages.inc b/profile2.pages.inc
new file mode 100644
index 0000000..1ebff1c
--- /dev/null
+++ b/profile2.pages.inc
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * @file
+ * Page and form callbacks for profiles.
+ */
+
+use Drupal\profile2\Profile;
+
+/**
+ * Confirmation form for deleting a profile.
+ */
+function profile2_delete_confirm_form($form, $form_state, Profile $profile) {
+  $form_state['profile'] = $profile;
+  $confirm_question = t('Are you sure you want to delete profile %label?', array('%label' => $profile->label()));
+  $uri = $profile->uri();
+  return confirm_form($form, $confirm_question, $uri['path']);
+}
+
+/**
+ * Submit handler for deleting a profile.
+ */
+function profile2_delete_confirm_form_submit(array $form, array &$form_state) {
+  $uri = $form_state['profile']->user()->uri();
+  $form_state['profile']->delete();
+  drupal_set_message(t('Deleted %label.', array('%label' => $form_state['profile']->label())));
+  $form_state['redirect'] = $uri['path'];
+}
