diff --git a/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp b/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp
index d1a9f270e68717e259c0964afd9f10fea8b747ca..8b71a0dd7bf215abc686775ab48cfc3d5f32de73 100644
--- a/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp
+++ b/Framework/PythonInterface/mantid/api/src/Exports/ITableWorkspace.cpp
@@ -296,6 +296,28 @@ PyObject *row(ITableWorkspace &self, int row) {
   return result;
 }
 
+/**
+ * Access a cell and return a corresponding Python type
+ * @param self A reference to the TableWorkspace python object that we were
+ * called on
+ * @param row An integer giving the row
+ */
+PyObject *columnTypes(ITableWorkspace &self) {
+  int numCols = static_cast<int>(self.columnCount());
+
+  PyObject *list = PyList_New(numCols);
+
+  for (int col = 0; col < numCols; col++) {
+    Mantid::API::Column_const_sptr column = self.getColumn(col);
+    const std::type_info &typeID = column->get_type_info();
+    if (PyList_SetItem(list, col, PyString_FromString(typeID.name()))) {
+      throw std::runtime_error("Error while building list");
+    }
+  }
+
+  return list;
+}
+
 /**
  * Adds a new row in the table, where the items are given in a dictionary
  * object mapping {column name:value}. It must contain a key-value entry for
@@ -629,6 +651,9 @@ void export_ITableWorkspace() {
       .def("row", &row, (arg("self"), arg("row")),
            "Return all values of a specific row as a dict.")
 
+      .def("columnTypes", &columnTypes, arg("self"),
+           "Return the types of the columns as a list")
+
       // FromSequence must come first since it takes an object parameter
       // Otherwise, FromDict will never be called as object accepts anything
       .def("addRow", &addRowFromSequence, (arg("self"), arg("row_items_seq")),
diff --git a/buildconfig/CMake/Bootstrap.cmake b/buildconfig/CMake/Bootstrap.cmake
index 36d10e1ed04468bf8af62222534d87fd7580b9cf..017f8f1ad14708c40f28aff535aed4ca299de16b 100644
--- a/buildconfig/CMake/Bootstrap.cmake
+++ b/buildconfig/CMake/Bootstrap.cmake
@@ -10,7 +10,7 @@ if( MSVC )
   include ( ExternalProject )
   set( EXTERNAL_ROOT ${PROJECT_SOURCE_DIR}/external CACHE PATH "Location to clone third party dependencies to" )
   set( THIRD_PARTY_GIT_URL "https://github.com/mantidproject/thirdparty-msvc2015.git" )
-  set ( THIRD_PARTY_GIT_SHA1 cee87b544761b0311dd3664f9dbbd2f11e0a780a )
+  set ( THIRD_PARTY_GIT_SHA1 11e8ce35bcfe21c26b503d09f424a96c70590523 )
   set ( THIRD_PARTY_DIR ${EXTERNAL_ROOT}/src/ThirdParty )
   # Generates a script to do the clone/update in tmp
   set ( _project_name ThirdParty )
diff --git a/qt/python/mantidqt/widgets/tableworkspacedisplay/model.py b/qt/python/mantidqt/widgets/tableworkspacedisplay/model.py
index 5a75197a9199f5e01397d0ee57d478265b6bd065..59203b78880325766877fd81d0e930bd852d5679 100644
--- a/qt/python/mantidqt/widgets/tableworkspacedisplay/model.py
+++ b/qt/python/mantidqt/widgets/tableworkspacedisplay/model.py
@@ -10,35 +10,73 @@
 #
 from __future__ import (absolute_import, division, print_function)
 
+
 from mantid.dataobjects import PeaksWorkspace, TableWorkspace
-from mantid.py3compat import Enum
-#  TODO remove transient mock dependency -> it is not available on Ubuntu fresh install
-# take MWD approach
-from mantidqt.widgets.matrixworkspacedisplay.test_helpers.matrixworkspacedisplay_common import MockWorkspace
 from mantidqt.widgets.tableworkspacedisplay.marked_columns import MarkedColumns
+from mantid.kernel import V3D
 
+import six
 
-class TableDisplayColumnType(Enum):
-    NUMERIC = 1
-    TEST = 123
+if six.PY2:
+    from functools32 import lru_cache
+else:
+    from functools import lru_cache
 
 
 class TableWorkspaceDisplayModel:
     SPECTRUM_PLOT_LEGEND_STRING = '{}-{}'
     BIN_PLOT_LEGEND_STRING = '{}-bin-{}'
 
+    ALLOWED_WORKSPACE_TYPES = [PeaksWorkspace, TableWorkspace]
+
     def __init__(self, ws):
-        if not isinstance(ws, TableWorkspace) \
-                and not isinstance(ws, PeaksWorkspace) \
-                and not isinstance(ws, MockWorkspace):
-            raise ValueError("The workspace type is not supported: {0}".format(type(ws)))
+        if not any(isinstance(ws, allowed_type) for allowed_type in self.ALLOWED_WORKSPACE_TYPES):
+            raise ValueError("The workspace type is not supported: {0}".format(ws))
 
         self.ws = ws
         self.ws_num_rows = self.ws.rowCount()
         self.ws_num_cols = self.ws.columnCount()
+        self.ws_column_types = self.ws.columnTypes()
+        self.convert_types = self.map_from_type_name(self.ws_column_types)
         self.marked_columns = MarkedColumns()
         self._original_column_headers = self.get_column_headers()
 
+    def _get_bool_from_str(self, string):
+        string = string.lower()
+        if string == "true":
+            return True
+        elif string == "false":
+            return False
+        else:
+            raise ValueError("'{}' is not a valid bool string.".format(string))
+
+    def _get_v3d_from_str(self, string):
+        if '[' in string and ']' in string:
+            string = string[1:-1]
+        if ',' in string:
+            return V3D(*[float(x) for x in string.split(',')])
+        else:
+            raise RuntimeError("'{}' is not a valid V3D string.".format(string))
+
+    def map_from_type_name(self, column_types):
+        convert_types = []
+        for type in column_types:
+            type = type.lower()
+            if 'int' in type:
+                convert_types.append(int)
+            elif 'double' in type or 'float' in type:
+                convert_types.append(float)
+            elif 'string' in type:
+                convert_types.append(str)
+            elif 'bool' in type:
+                convert_types.append(self._get_bool_from_str)
+            elif 'v3d' in type:
+                convert_types.append(self._get_v3d_from_str)
+            else:
+                raise ValueError("Trying to set data for unknown column type {}".format(type))
+
+        return convert_types
+
     def original_column_headers(self):
         return self._original_column_headers[:]
 
@@ -62,3 +100,11 @@ class TableWorkspaceDisplayModel:
 
     def get_column_header(self, index):
         return self.get_column_headers()[index]
+
+    @lru_cache(maxsize=1)
+    def is_peaks_workspace(self):
+        return isinstance(self.ws, PeaksWorkspace)
+
+    def set_cell_data(self, row, col, data):
+        data = self.convert_types[col](data)
+        self.ws.setCell(row, col, data)
diff --git a/qt/python/mantidqt/widgets/tableworkspacedisplay/presenter.py b/qt/python/mantidqt/widgets/tableworkspacedisplay/presenter.py
index 6fef3b2e01bcc9ad50694d70289312de9658aded..7229723f017836d43db46016f19155adb68e8758 100644
--- a/qt/python/mantidqt/widgets/tableworkspacedisplay/presenter.py
+++ b/qt/python/mantidqt/widgets/tableworkspacedisplay/presenter.py
@@ -14,6 +14,7 @@ from functools import partial
 from qtpy.QtCore import Qt
 from qtpy.QtWidgets import QTableWidgetItem
 
+from mantid.kernel import V3D
 from mantid.simpleapi import DeleteTableRows, StatisticsOfTableWorkspace
 from mantidqt.widgets.common.table_copying import copy_cells, show_mouse_toast, show_no_selection_to_copy_toast
 from mantidqt.widgets.tableworkspacedisplay.error_column import ErrorColumn
@@ -22,13 +23,35 @@ from .model import TableWorkspaceDisplayModel
 from .view import TableWorkspaceDisplayView
 
 
-class TableItem(QTableWidgetItem):
+class WorkbenchTableWidgetItem(QTableWidgetItem):
+    def __init__(self, data, editable=False):
+        # if not editable just initialise the ItemWidget as string
+        if not editable:
+            QTableWidgetItem.__init__(self, str(data))
+            self.setFlags(self.flags() & ~Qt.ItemIsEditable)
+            return
+
+        QTableWidgetItem.__init__(self)
+
+        if isinstance(data, V3D) or isinstance(data, float):
+            data = str(data)
+
+        self.original_data = data
+        # this will correctly turn all number cells into number types
+        self.reset()
+
     def __lt__(self, other):
         try:
             # if the data can be parsed as numbers then compare properly, otherwise default to the Qt implementation
             return float(self.data(Qt.DisplayRole)) < float(other.data(Qt.DisplayRole))
         except:
-            return super(TableItem, self).__lt__(other)
+            return super(WorkbenchTableWidgetItem, self).__lt__(other)
+
+    def reset(self):
+        self.setData(Qt.DisplayRole, self.original_data)
+
+    def update(self):
+        self.original_data = self.data(Qt.DisplayRole)
 
 
 class TableWorkspaceDisplay(object):
@@ -51,6 +74,28 @@ class TableWorkspaceDisplay(object):
         self.update_column_headers()
         self.load_data(self.view)
 
+        # connect to cellChanged signal after the data has been loaded
+        # all consecutive triggers will be from user actions
+        self.view.itemChanged.connect(self.handleItemChanged)
+
+    def handleItemChanged(self, item):
+        """
+        :type item: WorkbenchTableWidgetItem
+        :param item:
+        :return:
+        """
+        print("Changed data in cell:", item, "ops:", dir(item))
+
+        try:
+            self.model.set_cell_data(item.row(), item.column(), item.data(Qt.DisplayRole))
+            item.update()
+        except ValueError:
+            show_mouse_toast("Error: Trying to set non-numeric data into a numeric column.")
+        except Exception as x:
+            show_mouse_toast("Unknown error occurred: {}".format(x))
+        finally:
+            item.reset()
+
     def update_column_headers(self):
         """
         :param extra_labels: Extra labels to be appended to the column headers.
@@ -75,10 +120,14 @@ class TableWorkspaceDisplay(object):
         table.setRowCount(num_rows)
 
         num_cols = self.model.get_number_of_columns()
+
+        # the table should be editable if the ws is not PeaksWS
+        editable = not self.model.is_peaks_workspace()
+
         for col in range(num_cols):
             column_data = self.model.get_column(col)
             for row in range(num_rows):
-                item = TableItem(str(column_data[row]))
+                item = WorkbenchTableWidgetItem(column_data[row], editable=editable)
                 table.setItem(row, col, item)
 
     def action_copy_cells(self):
@@ -272,7 +321,7 @@ class TableWorkspaceDisplay(object):
             except ValueError as e:
                 #     TODO log error?
                 self.view.show_warning(
-                    "One or more of the columns being plotted contain invalid data for MatPlotLib." \
+                    "One or more of the columns being plotted contain invalid data for MatPlotLib."
                     "\n\nError message:\n{}".format(e), "Invalid data - Mantid Workbench")
                 return
 
diff --git a/qt/python/mantidqt/widgets/tableworkspacedisplay/test/test_tableworkspacedisplay_model.py b/qt/python/mantidqt/widgets/tableworkspacedisplay/test/test_tableworkspacedisplay_model.py
index a3e64bd712db29f992ad258ce2e51d1b10617565..befbaf27538f13580a6b53556accb9ae2b30b1c4 100644
--- a/qt/python/mantidqt/widgets/tableworkspacedisplay/test/test_tableworkspacedisplay_model.py
+++ b/qt/python/mantidqt/widgets/tableworkspacedisplay/test/test_tableworkspacedisplay_model.py
@@ -18,10 +18,11 @@ from mantidqt.widgets.matrixworkspacedisplay.test_helpers.matrixworkspacedisplay
 from mantidqt.widgets.tableworkspacedisplay.model import TableWorkspaceDisplayModel
 
 
-# from mantid.simpleapi import CreateSampleWorkspace
-
-
 class TableWorkspaceDisplayModelTest(unittest.TestCase):
+    @classmethod
+    def setUpClass(cls):
+        # Allow the MockWorkspace to work within the model
+        TableWorkspaceDisplayModel.ALLOWED_WORKSPACE_TYPES.append(MockWorkspace)
 
     def test_get_name(self):
         ws = MockWorkspace()
@@ -35,17 +36,26 @@ class TableWorkspaceDisplayModelTest(unittest.TestCase):
         self.assertRaises(ValueError, lambda: TableWorkspaceDisplayModel([]))
         self.assertRaises(ValueError, lambda: TableWorkspaceDisplayModel(1))
         self.assertRaises(ValueError, lambda: TableWorkspaceDisplayModel("test_string"))
- 
-    # def test_no_raise_with_supported_workspace(self):
-    #     ws = MockWorkspace()
-    #     expected_name = "TEST_WORKSPACE"
-    #     ws.name = Mock(return_value=expected_name)
-    #
-    #     # no need to assert anything - if the constructor raises the test will fail
-    #     TableWorkspaceDisplayModel(ws)
-    #
-    #     ws = CreateSampleWorkspace(NumBanks=1, BankPixelWidth=4, NumEvents=10)
-    #     TableWorkspaceDisplayModel(ws)
+
+
+class TableWorkspaceDisplayModelTestWithFramework(unittest.TestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        # Allow the MockWorkspace to work within the model
+        TableWorkspaceDisplayModel.ALLOWED_WORKSPACE_TYPES.append(MockWorkspace)
+
+    def test_no_raise_with_supported_workspace(self):
+        from mantid.simpleapi import CreateSampleWorkspace  # noqa
+        ws = MockWorkspace()
+        expected_name = "TEST_WORKSPACE"
+        ws.name = Mock(return_value=expected_name)
+
+        # no need to assert anything - if the constructor raises the test will fail
+        TableWorkspaceDisplayModel(ws)
+
+        ws = CreateSampleWorkspace(NumBanks=1, BankPixelWidth=4, NumEvents=10)
+        TableWorkspaceDisplayModel(ws)
 
 
 if __name__ == '__main__':
diff --git a/qt/python/mantidqt/widgets/tableworkspacedisplay/test_helpers/__init__.py b/qt/python/mantidqt/widgets/tableworkspacedisplay/test_helpers/__init__.py
deleted file mode 100644
index 57d5ae5a28a63ed0dd44886f201c25df7cac61ca..0000000000000000000000000000000000000000
--- a/qt/python/mantidqt/widgets/tableworkspacedisplay/test_helpers/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Mantid Repository : https://github.com/mantidproject/mantid
-#
-# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
-#     NScD Oak Ridge National Laboratory, European Spallation Source
-#     & Institut Laue - Langevin
-# SPDX - License - Identifier: GPL - 3.0 +
-#  This file is part of the mantid workbench.
-#
-#
diff --git a/qt/python/mantidqt/widgets/tableworkspacedisplay/test_helpers/mock_tableworkspacedisplay.py b/qt/python/mantidqt/widgets/tableworkspacedisplay/test_helpers/mock_tableworkspacedisplay.py
deleted file mode 100644
index 072b0f512d5eebfecdf5d361441e30d4d081bfe6..0000000000000000000000000000000000000000
--- a/qt/python/mantidqt/widgets/tableworkspacedisplay/test_helpers/mock_tableworkspacedisplay.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# Mantid Repository : https://github.com/mantidproject/mantid
-#
-# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
-#     NScD Oak Ridge National Laboratory, European Spallation Source
-#     & Institut Laue - Langevin
-# SPDX - License - Identifier: GPL - 3.0 +
-#  This file is part of the mantid workbench.
-#
-#
-from mock import Mock
-
-from mantidqt.widgets.TableWorkspacedisplay.table_view_model import TableWorkspaceTableViewModelType
-
-
-class MockQTableHeader(object):
-    def __init__(self):
-        self.addAction = Mock()
-
-
-class MockQSelection:
-    def __init__(self):
-        self.mock_item_range = MockQItemRange()
-        self.first = Mock(return_value=self.mock_item_range)
-
-
-class MockQItemRange(object):
-    def __init__(self):
-        self.top = Mock(return_value=0)
-        self.bottom = Mock(return_value=2)
-        self.left = Mock(return_value=0)
-        self.right = Mock(return_value=2)
-
-
-class MockQSelectionModel:
-    def __init__(self):
-        self.hasSelection = Mock()
-        self.selectedRows = None
-        self.selectedColumns = None
-        self.currentIndex = None
-        self.mock_selection = MockQSelection()
-        self.selection = Mock(return_value=self.mock_selection)
-
-
-class MockQTableViewModel:
-    def __init__(self):
-        self.type = TableWorkspaceTableViewModelType.x
-
-
-class MockQTableView:
-    def __init__(self):
-        self.setContextMenuPolicy = Mock()
-        self.addAction = Mock()
-        self.mock_horizontalHeader = MockQTableHeader()
-        self.mock_verticalHeader = MockQTableHeader()
-        self.horizontalHeader = Mock(return_value=self.mock_horizontalHeader)
-        self.verticalHeader = Mock(return_value=self.mock_verticalHeader)
-        self.setModel = Mock()
-        self.mock_model = MockQTableViewModel()
-        self.model = Mock(return_value=self.mock_model)
-
-        self.mock_selection_model = MockQSelectionModel()
-
-        self.selectionModel = Mock(return_value=self.mock_selection_model)
-
-
-class MockTableWorkspaceDisplayView:
-    def __init__(self):
-        self.set_context_menu_actions = Mock()
-        self.table_x = MockQTableView()
-        self.table_y = MockQTableView()
-        self.table_e = MockQTableView()
-        self.set_model = Mock()
-        self.copy_to_clipboard = Mock()
-        self.show_mouse_toast = Mock()
-        self.ask_confirmation = None
-
-
-class MockTableWorkspaceDisplayModel:
-    def __init__(self):
-        self.get_spectrum_plot_label = Mock()
-        self.get_bin_plot_label = Mock()
diff --git a/qt/python/mantidqt/widgets/tableworkspacedisplay/view.py b/qt/python/mantidqt/widgets/tableworkspacedisplay/view.py
index 75ac2cd389451e9276580f5bc854021b30aa3e54..8f567eaa40fe89ab1d6d6ffc02a2cd7e8e6af3ad 100644
--- a/qt/python/mantidqt/widgets/tableworkspacedisplay/view.py
+++ b/qt/python/mantidqt/widgets/tableworkspacedisplay/view.py
@@ -43,6 +43,7 @@ class TableWorkspaceDisplayView(QTableWidget):
         self.resize(600, 400)
         self.show()
 
+
     def doubleClickedHeader(self):
         print("Double clicked WOO")
 
@@ -114,8 +115,8 @@ class TableWorkspaceDisplayView(QTableWidget):
         set_as_y = QAction(self.TBD, "Set as Y", menu_main)
         set_as_y.triggered.connect(self.presenter.action_set_as_y)
 
-        set_as_nein = QAction(self.TBD, "Set as None", menu_main)
-        set_as_nein.triggered.connect(self.presenter.action_set_as_none)
+        set_as_none = QAction(self.TBD, "Set as None", menu_main)
+        set_as_none.triggered.connect(self.presenter.action_set_as_none)
 
         statistics_on_columns = QAction(self.STATISTICS_ON_ROW, "Statistics on Columns", menu_main)
         statistics_on_columns.triggered.connect(self.presenter.action_statistics_on_columns)
@@ -137,21 +138,24 @@ class TableWorkspaceDisplayView(QTableWidget):
         menu_main.addAction(set_as_x)
         menu_main.addAction(set_as_y)
 
-        # get the columns marked as Y
         marked_y_cols = self.presenter.get_columns_marked_as_y()
         num_y_cols = len(marked_y_cols)
+
+        # If any columns are marked as Y then generate the set error menu
         if num_y_cols > 0:
             menu_set_as_y_err = QMenu("Set error for Y...")
             for col in range(num_y_cols):
-                # get the real index of the column
-                # display the real index in the menu
                 set_as_y_err = QAction(self.TBD, "Y{}".format(col), menu_main)
+                # the column index of the column relative to the whole table, this is necessary
+                # so that later the data of the column marked as error can be retrieved
                 real_column_index = marked_y_cols[col]
+                # col here holds the index in the LABEL (multiple Y columns have labels Y0, Y1, YN...)
+                # this is NOT the same as the column relative to the WHOLE table
                 set_as_y_err.triggered.connect(partial(self.presenter.action_set_as_y_err, real_column_index, col))
                 menu_set_as_y_err.addAction(set_as_y_err)
             menu_main.addMenu(menu_set_as_y_err)
 
-        menu_main.addAction(set_as_nein)
+        menu_main.addAction(set_as_none)
         menu_main.addAction(self.make_separator(menu_main))
         menu_main.addAction(statistics_on_columns)
         menu_main.addAction(self.make_separator(menu_main))
@@ -189,4 +193,4 @@ class TableWorkspaceDisplayView(QTableWidget):
         return True if reply == QMessageBox.Yes else False
 
     def show_warning(self, message, title="Mantid Workbench"):
-        QMessageBox.warning(self, title, message)
\ No newline at end of file
+        QMessageBox.warning(self, title, message)