diff --git field_collection.module field_collection.module
index 055ef0a..835cdcd 100644
--- field_collection.module
+++ field_collection.module
@@ -496,10 +496,11 @@
 function field_collection_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
   foreach ($items as &$item) {
     // In case the entity has been loaded / created, save it and set the id.
-    if (isset($item['entity']) && !empty($item['entity']->is_new)) {
+    if (isset($item['entity']) /*&& !empty($item['entity']->is_new)*/) {
       $item['entity']->setHostEntity($entity_type, $entity);
+      entity_get_controller('field_collection_item')->save($item['entity']);
       // Pass FALSE, as we the host entity is already being saved.
-      $item['entity']->save(FALSE);
+      //$item['entity']->save(FALSE);
       $item = array('value' => $item['entity']->item_id);
     }
   }
@@ -532,7 +533,34 @@
  * Implements hook_field_is_empty().
  */
 function field_collection_field_is_empty($item, $field) {
-  return empty($item['value']);
+  if (!empty($item['value'])) {
+    return FALSE;
+  }
+  elseif (isset($item['entity'])) {
+    $field_collection_item = $item['entity'];
+    $field_collection_instances = field_info_instances('field_collection_item', $field['field_name']);
+
+    foreach ($field_collection_instances as $instance) {
+      $field_collection_field_name = $instance['field_name'];
+      $field_collection_field = field_info_field($field_collection_field_name);
+
+      // Determine the list of languages to iterate on.
+      $available_languages = field_available_languages('field_collection_item', $field_collection_field);
+      $languages = _field_language_suggestion($available_languages, NULL, $field_collection_field_name);
+
+      foreach ($languages as $langcode) {
+        $items = isset($field_collection_item->{$field_collection_field_name}[$langcode]) ? $field_collection_item->{$field_collection_field_name}[$langcode] : array();
+        $function = $field_collection_field['module'] . '_field_is_empty';
+        foreach ($items as $field_collection_field_item) {
+          if (!$function($field_collection_field_item, $field_collection_field)) {
+            // At least one (sub)field is not empty; the field-collection-item is not empty.
+            return FALSE;
+          }
+        }
+      }
+    }
+  }
+  return TRUE;
 }
 
 /**
@@ -712,10 +740,116 @@
   return array(
     'field_collection_hidden' => array(
       'label' => t('Hidden'),
+      'field types' => array('field_collection'),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
+        'default value' => FIELD_BEHAVIOR_CUSTOM,
+      ),
+    ),
+    'field_collection_subform' => array(
+      'label' => t('Subform'),
       'field types' => array('field_collection'),
+      'behaviors' => array(
+        'multiple values' => FIELD_BEHAVIOR_DEFAULT,
+        'default value' => FIELD_BEHAVIOR_CUSTOM,
+      ),
     ),
   );
 }
+
+/**
+ * Implements hook_field_widget_form().
+ */
+function field_collection_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
+  switch ($instance['widget']['type']) {
+    case 'field_collection_hidden':
+      return $element;
+
+    case 'field_collection_subform':
+      $field_name = $element['#field_name'];
+      $field_state = field_form_get_state($element['#field_parents'], $field_name, $langcode, $form_state);
+
+      if (isset($items[$delta]['entity'])) {
+        $field_collection_item = $items[$delta]['entity'];
+      }
+      elseif (isset($items[$delta]['value'])) {
+        $field_collection_item = field_collection_item_load($items[$delta]['value']);
+      }
+      if (empty($field_collection_item)) {
+        $field_collection_item = entity_create('field_collection_item', array('field_name' => $element['#field_name']));
+      }
+
+      // Nest the field-collection-item entity form in a dedicated parent space,
+      // by appending [field_name, langcode, delta] to the current parent space.
+      $parents = array_merge($element['#field_parents'], array($element['#field_name'], $element['#language'], $element['#delta']));
+
+      $element += array(
+        // @todo - properly declare element type in hook_element_info().
+        '#type' => 'field_collection_widget',
+        '#input' => TRUE,
+        '#element_validate' => array('field_collection_field_widget_validate'),
+        '#parents' => $parents,
+      );
+
+      field_attach_form('field_collection_item', $field_collection_item, $element, $form_state, $element['#language']);
+
+      // @todo : not sure how 'required' should behave.
+
+      $field_state['items'][$delta] = $field_collection_item;
+      field_form_set_state($element['#field_parents'], $field_name, $langcode, $form_state, $field_state);
+
+      return $element;
+  }
+}
+
+/**
+ * FAPI validation of an individual field-collection element.
+ */
+function field_collection_field_widget_validate($element, &$form_state, $complete_form) {
+  $instance = field_widget_instance($element, $form_state);
+
+  switch ($instance['widget']['type']) {
+    case 'field_collection_hidden':
+      return;
+
+    case 'field_collection_subform':
+      $field_name = $element['#field_name'];
+      $langcode = $element['#language'];
+      $delta = $element['#delta'];
+      $field_state = field_form_get_state($element['#field_parents'], $field_name, $langcode, $form_state);
+
+      // Reassemble a sub-entity object by merging submitted values and the base
+      // ids.
+      $field_collection_item = $field_state['items'][$delta];
+
+      // Validate the sub-fields.
+      $errors = form_get_errors();
+      field_attach_form_validate('field_collection_item', $field_collection_item, $element, $form_state);
+
+      // If validating the sub-fields did not raise errors, treat the submitted
+      // values and set the element value to the resulting sub-entity.
+      if (count(form_get_errors()) == count($errors)) {
+        field_attach_submit('field_collection_item', $field_collection_item, $element, $form_state);
+
+        $item = array('entity' => $field_collection_item);
+        if (empty($field_collection_item->is_new)) {
+          $item['value'] = $field_collection_item->item_id;
+        }
+        form_set_value($element, $item, $form_state);
+      }
+
+      $field_state['items'][$delta] = $field_collection_item;
+      field_form_set_state($element['#field_parents'], $field_name, $langcode, $form_state, $field_state);
+  }
+}
+
+/**
+ * Implements hook_field_widget_error().
+ */
+function field_collection_field_widget_error($element, $error, $form, &$form_state) {
+  // @todo - when hook_field_validate() raises an error (none for now),
+  // form_error($element, $error['message']);
+}
 
 /**
  * Implements hook_field_create_field().
