diff --git a/Framework/Kernel/CMakeLists.txt b/Framework/Kernel/CMakeLists.txt
index a7e6585ff5e0965e821e8409aaedf90337b69f80..308be7b94628c5f27ab0ac84c8c33dd0c1e15ee9 100644
--- a/Framework/Kernel/CMakeLists.txt
+++ b/Framework/Kernel/CMakeLists.txt
@@ -90,6 +90,7 @@ set ( SRC_FILES
 	src/PropertyManagerProperty.cpp
 	src/PropertyNexus.cpp
 	src/PropertyWithValue.cpp
+	src/PropertyWithValueJSONDecoder.cpp
 	src/ProxyInfo.cpp
 	src/PseudoRandomNumberGenerator.cpp
 	src/Quat.cpp
@@ -163,7 +164,7 @@ set ( INC_FILES
 	inc/MantidKernel/ConfigService.h
 	inc/MantidKernel/ConfigObserver.h
 	inc/MantidKernel/ConfigPropertyObserver.h
-        inc/MantidKernel/DateAndTime.h
+	inc/MantidKernel/DateAndTime.h
 	inc/MantidKernel/DataItem.h
 	inc/MantidKernel/DataService.h
 	inc/MantidKernel/DateAndTimeHelpers.h
@@ -242,7 +243,7 @@ set ( INC_FILES
 	inc/MantidKernel/NetworkProxy.h
 	inc/MantidKernel/NeutronAtom.h
 	inc/MantidKernel/NexusDescriptor.h
-        inc/MantidKernel/normal_distribution.h
+	inc/MantidKernel/normal_distribution.h
 	inc/MantidKernel/NullValidator.h
 	inc/MantidKernel/OptionalBool.h
 	inc/MantidKernel/ParaViewVersion.h
@@ -260,6 +261,7 @@ set ( INC_FILES
 	inc/MantidKernel/PropertyManager_fwd.h
 	inc/MantidKernel/PropertyNexus.h
 	inc/MantidKernel/PropertyWithValue.h
+	inc/MantidKernel/PropertyWithValueJSONDecoder
 	inc/MantidKernel/ProxyInfo.h
 	inc/MantidKernel/PseudoRandomNumberGenerator.h
 	inc/MantidKernel/QuasiRandomNumberSequence.h
@@ -410,6 +412,7 @@ set ( TEST_FILES
 	PropertyNexusTest.h
 	PropertyTest.h
 	PropertyWithValueTest.h
+  PropertyWithValueJSONDecoderTest.h
 	ProxyInfoTest.h
 	QuatTest.h
 	ReadLockTest.h
diff --git a/Framework/Kernel/inc/MantidKernel/PropertyWithValueJSONDecoder.h b/Framework/Kernel/inc/MantidKernel/PropertyWithValueJSONDecoder.h
new file mode 100644
index 0000000000000000000000000000000000000000..9809308a680ffc8eec415f3c4200c799edade731
--- /dev/null
+++ b/Framework/Kernel/inc/MantidKernel/PropertyWithValueJSONDecoder.h
@@ -0,0 +1,27 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright © 2007 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef PROPERTYWITHVALUEJSONDECODER_H
+#define PROPERTYWITHVALUEJSONDECODER_H
+
+#include "MantidKernel/DllConfig.h"
+#include <memory>
+
+namespace Json {
+class Value;
+}
+
+namespace Mantid {
+namespace Kernel {
+class Property;
+
+/// Attempt to create a Property from a Json value object
+MANTID_KERNEL_DLL std::unique_ptr<Property> decode(const Json::Value &value);
+
+} // namespace Kernel
+} // namespace Mantid
+
+#endif // PROPERTYWITHVALUEJSONDECODER_H
diff --git a/Framework/Kernel/src/PropertyWithValueJSONDecoder.cpp b/Framework/Kernel/src/PropertyWithValueJSONDecoder.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0658d31969c268d609e7594dcc50cc7ae90772da
--- /dev/null
+++ b/Framework/Kernel/src/PropertyWithValueJSONDecoder.cpp
@@ -0,0 +1,100 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2007 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#include "MantidKernel/PropertyWithValueJSONDecoder.h"
+#include "MantidKernel/PropertyWithValue.h"
+#include <json/json.h>
+#include <unordered_map>
+
+using Json::StreamWriterBuilder;
+using Json::Value;
+using Json::writeString;
+
+namespace Mantid {
+namespace Kernel {
+
+namespace {
+// Define a lookup mapping Json::ValueTypes to functions able to
+// create a PropertyWithValue object from that type
+using FromJsonFn = std::function<std::unique_ptr<Property>(
+    const std::string &, const Json::Value &)>;
+using FromJsonConverters = std::map<Json::ValueType, FromJsonFn>;
+
+// A pointer to a member function for doing the Json::Value->C++ type conversion
+template <typename T> using ValueAsTypeMemFn = T (Json::Value::*)() const;
+
+// A generic function accepting a pointer to a Json::Value::as* function, e.g.
+// asInt, plus the name and value of the property
+template <typename ValueType>
+std::unique_ptr<Property> fromJson(ValueAsTypeMemFn<ValueType> asFn,
+                                   const std::string &name,
+                                   const Json::Value &value) {
+  return std::make_unique<PropertyWithValue<ValueType>>(name,
+                                                        (value.*(asFn))());
+}
+
+// Returns (and creates on first call) the map of Json::ValueType to
+// FromJsonFn for converting a JsonValue to a Property object
+const FromJsonConverters &converters() {
+  static FromJsonConverters converters;
+  if (converters.empty()) {
+    using namespace std::placeholders;
+    // Build a map of Json types to fromJson functions of the appropriate type
+    converters.insert(std::make_pair(
+        Json::booleanValue,
+        std::bind(fromJson<bool>, &Json::Value::asBool, _1, _2)));
+    converters.insert(std::make_pair(
+        Json::intValue, std::bind(fromJson<int>, &Json::Value::asInt, _1, _2)));
+    converters.insert(std::make_pair(
+        Json::realValue,
+        std::bind(fromJson<double>, &Json::Value::asDouble, _1, _2)));
+    converters.insert(std::make_pair(
+        Json::stringValue,
+        std::bind(fromJson<std::string>, &Json::Value::asString, _1, _2)));
+  }
+  return converters;
+}
+
+/**
+ * @brief Create a PropertyWithValue object from the given Json::Value
+ * @param name The name of the new property
+ * @param value The value as Json::Value
+ * @return A pointer to a new Property object
+ * @throws std::invalid_argument if the type of the Json::Value is not known
+ */
+std::unique_ptr<Property> createProperty(const std::string &name,
+                                         const Json::Value &value) {
+  auto conversionFnIter = converters().find(value.type());
+  if (conversionFnIter == converters().end()) {
+    throw std::invalid_argument(
+        "Cannot create property with name " + name +
+        ". Unable to find converter for Json::ValueType to C++ type");
+  }
+  return conversionFnIter->second(name, value);
+}
+
+} // namespace
+
+/**
+ * @brief decode
+ * @param value A value as a Json serialized quantity
+ * @return
+ */
+std::unique_ptr<Property> decode(const Json::Value &value) {
+  if (value.size() != 1) {
+    StreamWriterBuilder wbuilder;
+    throw std::invalid_argument(
+        "Expected Json::Value with a single member. Found " +
+        writeString(wbuilder, value));
+  }
+  Value::Members members(value.getMemberNames());
+  assert(members.size() == 1);
+
+  return createProperty(members[0], value[members.front()]);
+}
+
+} // namespace Kernel
+} // namespace Mantid
diff --git a/Framework/Kernel/test/PropertyWithValueJSONDecoderTest.h b/Framework/Kernel/test/PropertyWithValueJSONDecoderTest.h
new file mode 100644
index 0000000000000000000000000000000000000000..8ffed9ca21f7b65882e36e615dc2d7625d3e7dd6
--- /dev/null
+++ b/Framework/Kernel/test/PropertyWithValueJSONDecoderTest.h
@@ -0,0 +1,86 @@
+// Mantid Repository : https://github.com/mantidproject/mantid
+//
+// Copyright &copy; 2007 ISIS Rutherford Appleton Laboratory UKRI,
+//     NScD Oak Ridge National Laboratory, European Spallation Source
+//     & Institut Laue - Langevin
+// SPDX - License - Identifier: GPL - 3.0 +
+#ifndef PROPERTYWITHVALUEJSONDECODERTEST_H
+#define PROPERTYWITHVALUEJSONDECODERTEST_H
+
+#include <cxxtest/TestSuite.h>
+#include <jsoncpp/json/value.h>
+
+#include "MantidKernel/PropertyWithValue.h"
+#include "MantidKernel/PropertyWithValueJSONDecoder.h"
+
+class PropertyWithValueJSONDecoderTest : public CxxTest::TestSuite {
+public:
+  static PropertyWithValueJSONDecoderTest *createSuite() {
+    return new PropertyWithValueJSONDecoderTest;
+  }
+
+  static void destroySuite(PropertyWithValueJSONDecoderTest *suite) {
+    return delete suite;
+  }
+
+  void testDecodeSingleJSONIntAsProperty() {
+    doSimpleObjectDecodeTest("IntProperty", 10);
+  }
+
+  void testDecodeSingleJSONDoubleAsProperty() {
+    doSimpleObjectDecodeTest("DoubleProperty", 10.5);
+  }
+
+  void testDecodeSingleJSONStringAsProperty() {
+    doSimpleObjectDecodeTest("StringProperty", std::string("My value"));
+  }
+
+  void testDecodeSingleJSONBoolAsProperty() {
+    doSimpleObjectDecodeTest("BoolProperty", false);
+  }
+
+  // ----------------------- Failure tests -----------------------
+
+  void testDecodeThrowsWithEmptyValue() {
+    using Mantid::Kernel::decode;
+    Json::Value root;
+    TSM_ASSERT_THROWS("Expected decode to throw for empty value", decode(root),
+                      std::invalid_argument);
+  }
+
+  void testDecodeThrowsWithGreaterThanOneMember() {
+    using Mantid::Kernel::decode;
+    Json::Value root;
+    root["one"] = 1;
+    root["two"] = 2;
+
+    TSM_ASSERT_THROWS("Expected decode to throw with more than 1 member",
+                      decode(root), std::invalid_argument);
+  }
+
+  void testDecodeThrowsWithNonObjectValue() {
+    using Mantid::Kernel::decode;
+    TSM_ASSERT_THROWS("Expected decode to throw with non-object type",
+                      decode(Json::Value(10)), std::invalid_argument);
+  }
+
+private:
+  template <typename ValueType>
+  void doSimpleObjectDecodeTest(const std::string &propName,
+                                const ValueType &propValue) {
+    Json::Value root;
+    root[propName] = propValue;
+
+    using Mantid::Kernel::decode;
+    auto property = decode(root);
+    TSM_ASSERT("Decode failed to create a Property. ", property);
+    using Mantid::Kernel::PropertyWithValue;
+    auto typedProperty =
+        dynamic_cast<PropertyWithValue<ValueType> *>(property.get());
+    TSM_ASSERT("Property has unexpected type ", typedProperty);
+    TS_ASSERT_EQUALS(propName, typedProperty->name());
+    TS_ASSERT_EQUALS(propValue, (*typedProperty)());
+  }
+};
+
+#endif // PROPERTYWITHVALUEJSONDECODERTEST_H