diff --git a/src/Element/Tablefield.php b/src/Element/Tablefield.php
index 1b3a8f3..c861ec2 100644
--- a/src/Element/Tablefield.php
+++ b/src/Element/Tablefield.php
@@ -28,6 +28,7 @@ class Tablefield extends FormElement {
       '#input_type' => 'textfield',
       '#rebuild' => FALSE,
       '#import' => FALSE,
+      '#editor' => FALSE,
       '#process' => [
         [$class, 'processTablefield'],
       ],
@@ -108,24 +109,35 @@ class Tablefield extends FormElement {
       $draggable = TRUE;
       for ($ii = 0; $ii < $cols; $ii++) {
         if (!empty($element['#locked_cells'][$i][$ii]) && !empty($element['#lock'])) {
+          if (is_array($element['#locked_cells'][$i][$ii]) && isset($element['#locked_cells'][$i][$ii]['value']) && isset($element['#locked_cells'][$i][$ii]['format'])) {
+            $cell_value = $element['#locked_cells'][$i][$ii]['value'];
+            $cell_format = $element['#locked_cells'][$i][$ii]['format'];
+          }
+          else {
+            $cell_value = $element['#locked_cells'][$i][$ii];
+            $cell_format = NULL;
+          }
+          $cell_rendered = !empty($cell_format) ? check_markup($cell_value, $cell_format) : $cell_value;
           $draggable = FALSE;
           $weightedRows[$i][$ii] = [
             '#type' => 'item',
-            '#value' => $element['#locked_cells'][$i][$ii],
-            '#title' => $element['#locked_cells'][$i][$ii],
+            '#value' => $cell_rendered,
+            '#title' => $cell_rendered,
           ];
         }
         else {
           $cell_value = $value[$i][$ii] ?? '';
+          $cell_rendered = is_array($cell_value) && isset($cell_value['value']) ? $cell_value['value'] : $cell_value;
           $weightedRows[$i][$ii] = [
-            '#type' => $input_type,
+            '#type' => $element['#editor'] ? 'text_format' : $input_type,
             '#maxlength' => 2048,
             '#size' => 0,
             '#attributes' => [
               'class' => ['tablefield-row-' . $i, 'tablefield-col-' . $ii],
               'style' => 'width:100%',
             ],
-            '#default_value' => $cell_value,
+            '#default_value' => $cell_rendered,
+            '#format' => is_array($cell_value) && isset($cell_value['format']) ? $cell_value['format'] : NULL,
           ];
         }
       }
@@ -288,8 +300,7 @@ class Tablefield extends FormElement {
     $parents = array_slice($triggering_element['#array_parents'], 0, -2, TRUE);
     $rebuild = NestedArray::getValue($form, $parents);
 
-    // We don't want to re-send the format/_weight options.
-    unset($rebuild['format']);
+    // We don't want to re-send the _weight option.
     unset($rebuild['_weight']);
 
     // Set row value to default only if there is Add Row button clicked.
@@ -331,6 +342,25 @@ class Tablefield extends FormElement {
       $imported_tablefield = static::importCsv($id);
 
       if ($imported_tablefield) {
+        $array_parents = array_slice($triggering_element['#array_parents'], 0, -2, TRUE);
+        $element = NestedArray::getValue($form, $array_parents);
+
+        $array_element_parents = array_slice($triggering_element['#array_parents'], 0, -3, TRUE);
+        $element_parents = NestedArray::getValue($form, $array_element_parents);
+
+        $value = $imported_tablefield['table'];
+        foreach ($value as $row => $row_value) {
+          foreach ($row_value as $col => $col_value) {
+            $col_el = $element['table'][$row][$col];
+            if ((empty($col_el) && $element_parents['#editor']) || (!empty($col_el) && $col_el['#type'] == 'text_format')) {
+              $imported_tablefield['table'][$row][$col] = [
+                'format' => $col_el['#format'],
+                'value' => $col_value
+              ];
+            }
+          }
+        }
+
         $form_state->setValue($parents, $imported_tablefield);
 
         $input = $form_state->getUserInput();
diff --git a/src/Plugin/Field/FieldFormatter/TablefieldFormatter.php b/src/Plugin/Field/FieldFormatter/TablefieldFormatter.php
index 779bd6d..b10b6f1 100644
--- a/src/Plugin/Field/FieldFormatter/TablefieldFormatter.php
+++ b/src/Plugin/Field/FieldFormatter/TablefieldFormatter.php
@@ -156,8 +156,10 @@ class TablefieldFormatter extends FormatterBase implements ContainerFactoryPlugi
         foreach ($tabledata as $row_key => $row) {
           foreach ($row as $col_key => $cell) {
             if (is_numeric($col_key)) {
+              $value = is_array($cell) && isset($cell['value']) ? $cell['value'] : $cell;
+              $format = is_array($cell) && isset($cell['format']) ? $cell['format'] : NULL;
               $tabledata[$row_key][$col_key] = [
-                'data' => empty($table->format) ? $cell : check_markup($cell, $table->format),
+                'data' => empty($format) ? $value : check_markup($value, $format),
                 'class' => ['row_' . $row_key, 'col_' . $col_key],
               ];
             }
diff --git a/src/Plugin/Field/FieldType/TablefieldItem.php b/src/Plugin/Field/FieldType/TablefieldItem.php
index 680f0c9..dac896f 100644
--- a/src/Plugin/Field/FieldType/TablefieldItem.php
+++ b/src/Plugin/Field/FieldType/TablefieldItem.php
@@ -34,15 +34,10 @@ class TablefieldItem extends FieldItemBase {
           'size' => 'big',
           'serialize' => TRUE,
         ],
-        'format' => [
-          'type' => 'varchar',
-          'length' => 255,
-          'default value' => '',
-        ],
         'caption' => [
           'type' => 'varchar',
           'length' => 255,
-          'default value' => '',
+          'default' => '',
         ],
       ],
     ];
@@ -140,9 +135,6 @@ class TablefieldItem extends FieldItemBase {
       ->setLabel(t('Table data'))
       ->setDescription(t('Stores tabular data.'));
 
-    $properties['format'] = DataDefinition::create('filter_format')
-      ->setLabel(t('Text format'));
-
     $properties['caption'] = DataDefinition::create('string')
       ->setLabel(t('Table Caption'));
 
diff --git a/src/Plugin/Field/FieldWidget/TablefieldWidget.php b/src/Plugin/Field/FieldWidget/TablefieldWidget.php
index 15d8a85..e76e5e0 100644
--- a/src/Plugin/Field/FieldWidget/TablefieldWidget.php
+++ b/src/Plugin/Field/FieldWidget/TablefieldWidget.php
@@ -175,10 +175,7 @@ class TablefieldWidget extends WidgetBase implements ContainerFactoryPluginInter
 
     // Allow the user to select input filters.
     if (!empty($field_settings['cell_processing'])) {
-      $element['#base_type'] = $element['#type'];
-      $element['#type'] = 'text_format';
-      $element['#format'] = $default_value->format ?? NULL;
-      $element['#editor'] = FALSE;
+      $element['#editor'] = TRUE;
     }
 
     return $element;
diff --git a/tablefield.install b/tablefield.install
index d5ea4fb..1e2e7de 100644
--- a/tablefield.install
+++ b/tablefield.install
@@ -5,6 +5,8 @@
  * Installation options for TableField.
  */
 
+use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
+
 /**
  * Add columns for caption field to the database.
  */
@@ -13,39 +15,149 @@ function tablefield_update_8001() {
     'type' => 'varchar',
     'length' => 255,
     'default' => '',
-    'not null' => TRUE,
+    'not null' => FALSE,
   ]);
 }
 
+/**
+ * Remove "format" column because each cell will use its own format.
+ */
+function tablefield_update_8002() {
+  tablefield_remove_existing_column('format');
+}
+
 /**
  * Helper function to add new columns to the field schema.
  *
- * @param string $column_name
+ * @param string $new_property_name
  *   The name of the column that will be added.
  * @param array $spec
  *   The options of the new column.
  */
-function tablefield_add_new_column($column_name, array $spec) {
-  $field_map = \Drupal::service('entity_field.manager')->getFieldMapByFieldType('tablefield');
+function tablefield_add_new_column(string $new_property_name, array $spec) {
   $schema = \Drupal::database()->schema();
+  $entity_type_manager = \Drupal::entityTypeManager();
+  $entity_field_manager = \Drupal::service('entity_field.manager');
+  $entity_field_map = $entity_field_manager->getFieldMapByFieldType('tablefield');
+  $entity_storage_schema_sql = \Drupal::keyValue('entity.storage_schema.sql');
+  /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */
+  $last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
 
-  foreach ($field_map as $entity_type_id => $fields) {
-    foreach (array_keys($fields) as $field_name) {
-      $tables = [
-        "{$entity_type_id}__$field_name",
-        "{$entity_type_id}_revision__$field_name",
-      ];
+  foreach ($entity_field_map as $entity_type_id => $fields) {
+    $entity_storage = $entity_type_manager->getStorage($entity_type_id);
+    if (!$entity_storage instanceof SqlEntityStorageInterface) {
+      continue;
+    }
+
+    /** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
+    $entity_type = $entity_type_manager->getDefinition($entity_type_id);
+    // Loads definitions for all fields.
+    $entity_field_storage_defintitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id);
+    /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
+    $table_mapping = $entity_storage->getTableMapping($entity_field_storage_defintitions);
 
-      $new_column_name = $field_name . '_' . $column_name;
+    // Intersect tablefield fields with storage definitions for all
+    // fields.
+    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $field_definitions */
+    $field_definitions = array_intersect_key($entity_field_storage_defintitions, $fields);
+
+    // Iterate over all tablefield field definitions for this entity type.
+    foreach ($field_definitions as $field_definition) {
+      $field_name = $field_definition->getName();
+      $tables = [];
+      $tables[] = $table_mapping->getFieldTableName($field_name);
+      if ($entity_type->isRevisionable() && $field_definition->isRevisionable()) {
+        $tables[] = $table_mapping->getDedicatedRevisionTableName($field_definition);
+      }
+
+      // Field type column names map to real table column names.
+      $columns = $table_mapping->getColumnNames($field_name);
+      $column_name = $columns[$new_property_name];
 
       foreach ($tables as $table) {
-        $field_exists = $schema->fieldExists($table, $new_column_name);
-        $table_exists = $schema->tableExists($table);
+        if (!$schema->fieldExists($table, $column_name)) {
+          $schema->addField($table, $column_name, $spec);
+        }
+      }
+
+      // Update the tracked entity table schema.
+      $schema_key = "$entity_type_id.field_schema_data.$field_name";
+      $field_schema_data = $entity_storage_schema_sql->get($schema_key);
+      foreach ($field_schema_data as $table_name => $field_schema) {
+        // Remove the column from the field schema data.
+        $field_schema_data[$table_name]['fields'][$column_name] = $spec;
+      }
+      $entity_storage_schema_sql->set($schema_key, $field_schema_data);
+
+      $definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id);
+      $definitions[$field_name] = $field_definition;
+      $last_installed_schema_repository->setLastInstalledFieldStorageDefinitions($entity_type_id, $definitions);
+    }
+  }
+}
+
+/**
+ * Helper function to remove columns from the field schema.
+ *
+ * @param string $property_to_remove
+ *   The name of the field that will be added.
+ */
+function tablefield_remove_existing_column(string $property_to_remove) {
+  $schema = \Drupal::database()->schema();
+  $entity_type_manager = \Drupal::entityTypeManager();
+  $entity_field_manager = \Drupal::service('entity_field.manager');
+  $entity_field_map = $entity_field_manager->getFieldMapByFieldType('tablefield');
+  $entity_storage_schema_sql = \Drupal::keyValue('entity.storage_schema.sql');
+  /** @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $last_installed_schema_repository */
+  $last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
+
+  foreach ($entity_field_map as $entity_type_id => $fields) {
+    $entity_storage = $entity_type_manager->getStorage($entity_type_id);
+    if (!$entity_storage instanceof SqlEntityStorageInterface) {
+      continue;
+    }
+
+    /** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
+    $entity_type = $entity_type_manager->getDefinition($entity_type_id);
+    // Loads definitions for all fields.
+    $entity_field_storage_defintitions = $entity_field_manager->getFieldStorageDefinitions($entity_type_id);
+    /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
+    $table_mapping = $entity_storage->getTableMapping($entity_field_storage_defintitions);
 
-        if (!$field_exists && $table_exists) {
-          $schema->addField($table, $new_column_name, $spec);
+    // Intersect tablefield fields with storage definitions for all
+    // fields.
+    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $field_definitions */
+    $field_definitions = array_intersect_key($entity_field_storage_defintitions, $fields);
+
+    // Iterate over all tablefield field definitions for this entity type.
+    foreach ($field_definitions as $field_definition) {
+      $field_name = $field_definition->getName();
+      $tables = [];
+      $tables[] = $table_mapping->getFieldTableName($field_name);
+      if ($entity_type->isRevisionable() && $field_definition->isRevisionable()) {
+        $tables[] = $table_mapping->getDedicatedRevisionTableName($field_definition);
+      }
+
+      $column_name = $field_name . '_' . $property_to_remove;
+
+      foreach ($tables as $table) {
+        if ($schema->fieldExists($table, $column_name)) {
+          $schema->dropField($table, $column_name);
         }
       }
+
+      // Update the tracked entity table schema.
+      $schema_key = "$entity_type_id.field_schema_data.$field_name";
+      $field_schema_data = $entity_storage_schema_sql->get($schema_key);
+      foreach ($field_schema_data as $table_name => $field_schema) {
+        // Remove the column from the field schema data.
+        unset($field_schema_data[$table_name]['fields'][$column_name]);
+      }
+      $entity_storage_schema_sql->set($schema_key, $field_schema_data);
+
+      $definitions = $last_installed_schema_repository->getLastInstalledFieldStorageDefinitions($entity_type_id);
+      $definitions[$field_name] = $field_definition;
+      $last_installed_schema_repository->setLastInstalledFieldStorageDefinitions($entity_type_id, $definitions);
     }
   }
 }
diff --git a/tablefield.post_update.php b/tablefield.post_update.php
index c3c8e90..436b6ea 100644
--- a/tablefield.post_update.php
+++ b/tablefield.post_update.php
@@ -40,7 +40,7 @@ function tablefield_post_update_implement_tablefield_entity_view_display_schema(
     ->update($sandbox, 'entity_view_display', function (EntityViewDisplayInterface $entityViewDisplay) {
       $updated = FALSE;
       foreach ($entityViewDisplay->getComponents() as $key => $component) {
-        if ($component['type'] === 'tablefield') {
+        if (isset($component['type']) && $component['type'] === 'tablefield') {
           $component['settings']['row_header'] = (bool) $component['settings']['row_header'];
           $component['settings']['column_header'] = (bool) $component['settings']['column_header'];
           $entityViewDisplay->setComponent($key, $component);
diff --git a/tests/src/Functional/TableValueFieldTest.php b/tests/src/Functional/TableValueFieldTest.php
index 8264180..70d66a9 100644
--- a/tests/src/Functional/TableValueFieldTest.php
+++ b/tests/src/Functional/TableValueFieldTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\tablefield\Functional;
 
+use Drupal\field\Entity\FieldConfig;
 use Drupal\Tests\BrowserTestBase;
 
 /**
@@ -21,7 +22,7 @@ class TableValueFieldTest extends BrowserTestBase {
   /**
    * {@inheritdoc}
    */
-  protected static $modules = ['node', 'tablefield'];
+  protected static $modules = ['node', 'tablefield', 'filter_test'];
 
   /**
    * {@inheritdoc}
@@ -75,4 +76,42 @@ class TableValueFieldTest extends BrowserTestBase {
     $assert_session->elementContains('css', 'table#tablefield-node-1-field_table-0 tbody tr td.row_2.col_2', 'Row 2-3');
   }
 
+  /**
+   * Create a node with with a tablefield and cell processing enabled.
+   */
+  public function testTablefieldCellProcessing() {
+    // Enable cell processing.
+    $field_config = FieldConfig::loadByName('node', 'article', 'field_table');
+    $field_config->setSetting('cell_processing', TRUE)->save();
+
+    $this->drupalGet('node/add/article');
+    $this->submitForm([
+      'title[0][value]' => 'Llamas are cool',
+      'field_table[0][tablefield][table][0][0][value]' => '<strong>Bold text</strong>',
+      'field_table[0][tablefield][table][0][0][format]' => 'filtered_html',
+      'field_table[0][tablefield][table][0][1][value]' => '<u>Forbidden HTML</u>',
+      'field_table[0][tablefield][table][0][1][format]' => 'filtered_html',
+      'field_table[0][tablefield][table][0][2][value]' => '<u>Underlined text.</u>',
+      'field_table[0][tablefield][table][0][2][format]' => 'full_html',
+    ], 'Save');
+
+    $assert_session = $this->assertSession();
+    $assert_session->pageTextContains('Article Llamas are cool has been created.');
+
+    // The <strong> tag is allowed by the filtered_html format, so this should
+    // be shown.
+    $assert_session->elementContains('css', 'table#tablefield-node-1-field_table-0 thead th.row_0.col_0', '<strong>Bold text</strong>');
+    // The <u> tag is not allowed by the filtered_html format, so this tag
+    // should be removed.
+    $assert_session->elementContains('css', 'table#tablefield-node-1-field_table-0 thead th.row_0.col_1', 'Forbidden');
+    // All HTML is allowed by the full_html format.
+    $assert_session->elementContains('css', 'table#tablefield-node-1-field_table-0 thead th.row_0.col_2', '<u>Underlined text.</u>');
+
+    // Check that the submitted data is correctly saved in the database.
+    $node = $this->drupalGetNodeByTitle('Llamas are cool');
+    $this->assertEquals(['value' => '<strong>Bold text</strong>', 'format' => 'filtered_html'], $node->get('field_table')->value[0][0]);
+    $this->assertEquals(['value' => '<u>Forbidden HTML</u>', 'format' => 'filtered_html'], $node->get('field_table')->value[0][1]);
+    $this->assertEquals(['value' => '<u>Underlined text.</u>', 'format' => 'full_html'], $node->get('field_table')->value[0][2]);
+  }
+
 }
