diff --git a/include/pdi/array_datatype.h b/include/pdi/array_datatype.h
index 3ef765cd6dd1792e4a71941573f4b47d9bd57684..78ba783c88161c825090127617bee632037bee6b 100644
--- a/include/pdi/array_datatype.h
+++ b/include/pdi/array_datatype.h
@@ -84,7 +84,9 @@ public:
 	
 	bool simple() const override;
 	
-	void* data_dense_copy(void* to, const void* from) const override;
+	void* data_to_dense_copy(void* to, const void* from) const override;
+	
+	void* data_from_dense_copy(void* to, const void* from) const override;
 	
 	void destroy_data(void* ptr) const override;
 	
diff --git a/include/pdi/data_descriptor.h b/include/pdi/data_descriptor.h
index 91fcaeea441a24e56a5cf2d2473a77f8f3bea783..2633cc95a80cfcbfd4645a1c9c81e62ac1e33dc8 100644
--- a/include/pdi/data_descriptor.h
+++ b/include/pdi/data_descriptor.h
@@ -64,7 +64,7 @@ public:
 	 */
 	virtual void metadata(bool metadata) = 0;
 	
-	/** Access the name of the 
+	/** Access the name of the descriptor
 	 */
 	virtual const std::string& name() const = 0;
 	
diff --git a/include/pdi/datatype.h b/include/pdi/datatype.h
index d3df5237ebbf701759da9ab9c487e22387d24b4e..31324382444bb3cb522dfb393cd50e75b69e3a49 100644
--- a/include/pdi/datatype.h
+++ b/include/pdi/datatype.h
@@ -99,12 +99,22 @@ public:
 	/**
 	 * Creates a dense deep copy of data
 	 *
-	 * \param[in] to the pointer to the alocated memory to fill
-	 * \param[in] from the pointer to the copied data
+	 * \param[in] to the pointer to the allocated memory to fill (dense data)
+	 * \param[in] from the pointer to the copied data (size of buffersize)
 	 *
 	 * \return updated `to' pointer
 	 */
-	virtual void* data_dense_copy(void* to, const void* from) const = 0;
+	virtual void* data_to_dense_copy(void* to, const void* from) const = 0;
+	
+	/**
+	 * Creates a sparse deep copy of dense data
+	 *
+	 * \param[in] to the pointer to the allocated memory to fill (size of buffersize)
+	 * \param[in] from the pointer to the copied data (dense data)
+	 *
+	 * \return updated `to' pointer
+	 */
+	virtual void* data_from_dense_copy(void* to, const void* from) const = 0;
 	
 	/**
 	 * Function used to delete the data behind the datatype. This should not deallocate the memory.
diff --git a/include/pdi/record_datatype.h b/include/pdi/record_datatype.h
index 25bee81170e85e298ff2e23e65e8aec22080dfda..a16a80c8b1340052fa45cbc74dd511b420a3130a 100644
--- a/include/pdi/record_datatype.h
+++ b/include/pdi/record_datatype.h
@@ -99,7 +99,9 @@ public:
 	
 	bool simple() const override;
 	
-	void* data_dense_copy(void* to, const void* from) const override;
+	void* data_to_dense_copy(void* to, const void* from) const override;
+	
+	void* data_from_dense_copy(void* to, const void* from) const override;
 	
 	void destroy_data(void* ptr) const override;
 	
diff --git a/include/pdi/scalar_datatype.h b/include/pdi/scalar_datatype.h
index f0e31fae9bd44666c9372432b262d0e04158fbeb..db35c3522cc2cb8bc8b906e40b7b1e41e5919bd6 100644
--- a/include/pdi/scalar_datatype.h
+++ b/include/pdi/scalar_datatype.h
@@ -83,7 +83,9 @@ public:
 	
 	bool simple() const override;
 	
-	void* data_dense_copy(void* to, const void* from) const override;
+	void* data_to_dense_copy(void* to, const void* from) const override;
+	
+	void* data_from_dense_copy(void* to, const void* from) const override;
 	
 	void destroy_data(void* ptr) const override;
 	
diff --git a/src/array_datatype.cxx b/src/array_datatype.cxx
index fa7eccbc64ad05a76942633cc8b85fcf158fe777..693fcf4c421fb688a54014f9e36ac2ca9534b84b 100644
--- a/src/array_datatype.cxx
+++ b/src/array_datatype.cxx
@@ -129,7 +129,7 @@ bool Array_datatype::simple() const
 	return m_subtype->simple();
 }
 
-void* Array_datatype::data_dense_copy(void* to, const void* from) const
+void* Array_datatype::data_to_dense_copy(void* to, const void* from) const
 {
 	size_t subtype_buffersize = subtype().buffersize();
 	from = static_cast<const uint8_t*>(from) + (start() * subtype_buffersize);
@@ -147,12 +147,44 @@ void* Array_datatype::data_dense_copy(void* to, const void* from) const
 		//size = 0, because we know that to points to allocated memory
 		to = std::align(subtype_alignment, 0, to, space_to_align);
 		
-		to = subtype().data_dense_copy(to, from);
+		to = subtype().data_to_dense_copy(to, from);
 		from = reinterpret_cast<const uint8_t*>(from) + subtype_buffersize;
 	}
 	return to;
 }
 
+void* Array_datatype::data_from_dense_copy(void* to, const void* from) const
+{
+	uint8_t* original_to = reinterpret_cast<uint8_t*>(to);
+	size_t subtype_buffersize = subtype().buffersize();
+	to = static_cast<uint8_t*>(to) + (start() * subtype_buffersize);
+	
+	if (subtype().simple() && subtype().dense()) {
+		//dense copy
+		memcpy(to, from, datasize());
+		to = original_to + buffersize();
+		return to;
+	}
+	
+	size_t subtype_alignment = subtype().alignment();
+	for (int subtype_no = 0; subtype_no < subsize(); subtype_no++) {
+		//space_to_align is set to alignment(), because we always find the alignment in the size of alignment
+		size_t space_to_align = subtype_alignment;
+		//size = 0, because we know that to points to allocated memory
+		to = std::align(subtype_alignment, 0, to, space_to_align);
+		
+		//cannot use std::aling, becasue `from' is const
+		auto subtype_align = subtype().alignment();
+		int padding = (subtype_align - (reinterpret_cast<const uintptr_t>(from) % subtype_align)) % subtype_align;
+		from = reinterpret_cast<const uint8_t*>(from) + padding;
+		
+		to = subtype().data_from_dense_copy(to, from);
+		from = reinterpret_cast<const uint8_t*>(from) + subtype().datasize();
+	}
+	to = original_to + buffersize();
+	return to;
+}
+
 void Array_datatype::destroy_data(void* ptr) const
 {
 	if (!subtype().simple()) {
diff --git a/src/record_datatype.cxx b/src/record_datatype.cxx
index d5d6d2b61f8b5da4fe55714c667819435e853f1d..c4a0a2503fd9b9e11e5628cfafbdd3528d345487 100644
--- a/src/record_datatype.cxx
+++ b/src/record_datatype.cxx
@@ -187,7 +187,7 @@ bool Record_datatype::simple() const
 	return true;
 }
 
-void* Record_datatype::data_dense_copy(void* to, const void* from) const
+void* Record_datatype::data_to_dense_copy(void* to, const void* from) const
 {
 	if (simple() && dense()) {
 		//dense copy
@@ -202,11 +202,35 @@ void* Record_datatype::data_dense_copy(void* to, const void* from) const
 		//size = 0, because we know that to points to allocated memory
 		to = std::align(member.type().alignment(), 0, to, space_to_align);
 		const uint8_t* member_from = reinterpret_cast<const uint8_t*>(from) + member.displacement();
-		to = member.type().data_dense_copy(to, member_from);
+		to = member.type().data_to_dense_copy(to, member_from);
 	}
 	return to;
 }
 
+void* Record_datatype::data_from_dense_copy(void* to, const void* from) const
+{
+	uint8_t* original_to = reinterpret_cast<uint8_t*>(to);
+	
+	if (simple() && dense()) {
+		//dense copy
+		memcpy(to, from, datasize());
+		to = original_to + buffersize();
+		return to;
+	}
+	
+	for (auto&& member : members()) {
+		auto member_align = member.type().alignment();
+		int padding = (member_align - (reinterpret_cast<const uintptr_t>(from) % member_align)) % member_align;
+		from = reinterpret_cast<const uint8_t*>(from) + padding;
+		to = original_to + member.displacement();
+		
+		member.type().data_from_dense_copy(to, from);
+		from = reinterpret_cast<const uint8_t*>(from) + member.type().datasize();
+	}
+	to = original_to + buffersize();
+	return to;
+}
+
 void Record_datatype::destroy_data(void* ptr) const
 {
 	if ( simple() ) return;
diff --git a/src/ref_any.cxx b/src/ref_any.cxx
index 0b9954c8ec6f05227b078eced6b0f86dc5fe7416..2c5ff93940f0e6756ddca40ac5bdfd47511867fa 100644
--- a/src/ref_any.cxx
+++ b/src/ref_any.cxx
@@ -50,7 +50,7 @@ Ref Ref_base::do_copy(Ref_r ref)
 	void* buffer = operator new (size);
 	void* data = std::align(densified_type->alignment(), densified_type->buffersize(), buffer, size);
 	try {
-		ref.type().data_dense_copy(data, ref.get());
+		ref.type().data_to_dense_copy(data, ref.get());
 	} catch (...) {
 		::operator delete (buffer);
 		throw;
diff --git a/src/scalar_datatype.cxx b/src/scalar_datatype.cxx
index 75a82ba37658f30b5f3b08f21b82324e7b34fab7..6688b69f344604f11630d41df6a0e59818e01cb2 100644
--- a/src/scalar_datatype.cxx
+++ b/src/scalar_datatype.cxx
@@ -124,7 +124,7 @@ bool Scalar_datatype::simple() const
 	return !m_copy && !m_destroy;
 }
 
-void* Scalar_datatype::data_dense_copy(void* to, const void* from) const
+void* Scalar_datatype::data_to_dense_copy(void* to, const void* from) const
 {
 	if ( !m_copy ) {
 		memcpy(to, from, datasize());
@@ -135,6 +135,11 @@ void* Scalar_datatype::data_dense_copy(void* to, const void* from) const
 	return to;
 }
 
+void* Scalar_datatype::data_from_dense_copy(void* to, const void* from) const
+{
+	return data_to_dense_copy(to, from);
+}
+
 void Scalar_datatype::destroy_data(void* ptr) const
 {
 	if ( m_destroy ) {
diff --git a/tests/PDI_array_datatype.cxx b/tests/PDI_array_datatype.cxx
index e5af47b44ebb043817763ab75bfdb05a69e5f932..28a376edfb3abe349b0fc1efe4c34dd64e857780 100644
--- a/tests/PDI_array_datatype.cxx
+++ b/tests/PDI_array_datatype.cxx
@@ -25,6 +25,7 @@
 #include <gtest/gtest.h>
 
 #include <pdi/array_datatype.h>
+#include <pdi/scalar_datatype.h>
 
 #include "mocks/context_mock.h"
 #include "mocks/datatype_mock.h"
@@ -265,3 +266,60 @@ TEST_F(ArrayDatatypeTest, check_alignment)
 	EXPECT_CALL(*this->mockDatatype, alignment()).WillOnce(Return(subtype_alignment));
 	ASSERT_EQ(subtype_alignment, this->test_array.alignment());
 }
+
+
+/*
+ * Struct prepared for SparseArrayDeepCopyTest.
+ *
+ */
+struct SparseArrayDeepCopyTest : public ::testing::Test {
+
+	int* sparse_array {new int[100]}; //buffer: 10 x 10; data: 4 x 4; start: (3, 3)
+	int* dense_array {new int[16]};
+	
+	SparseArrayDeepCopyTest()
+	{
+		for (int i = 0; i < 100; i++) {
+			sparse_array[i] = 0;
+		}
+		for (int i = 0; i < 16; i++) {
+			dense_array[i] = i;
+		}
+	}
+	
+	Datatype_uptr datatype {
+		new Array_datatype
+		{
+			Datatype_uptr {
+				new Array_datatype
+				{
+					Datatype_uptr{new Scalar_datatype {Scalar_kind::SIGNED, sizeof(int)}},
+					10,
+					3,
+					4
+				}
+			},
+			10,
+			3,
+			4
+		}
+	};
+};
+
+/*
+ * Name:                SparseArrayDeepCopyTest.dense_to_sparse
+ *
+ * Tested functions:    PDI::ArrayDatatypeTest::data_sparse_copy()
+ *
+ * Description:         Test checks if correct copy is returned
+ *
+ */
+TEST_F(SparseArrayDeepCopyTest, dense_to_sparse)
+{
+	this->datatype->data_from_dense_copy(sparse_array, dense_array);
+	for (int i = 3; i < 7; i++) {
+		for (int j = 3; j < 7; j++) {
+			ASSERT_EQ(dense_array[(i-3)*4 + j-3], sparse_array[10*i + j]);
+		}
+	}
+}
\ No newline at end of file
diff --git a/tests/PDI_record_datatype.cxx b/tests/PDI_record_datatype.cxx
index db76e80e6e1e50859c7792bcdbeee932df81a143..c5eeea55c4c81726e1ce586ad0eca8e1bf5cdb58 100644
--- a/tests/PDI_record_datatype.cxx
+++ b/tests/PDI_record_datatype.cxx
@@ -135,3 +135,123 @@ TYPED_TEST(RecordDatatypeTest, check_clone_type)
 	ASSERT_EQ(this->test_structure->test_record()->members().size(), newRecord->members().size());
 }
 
+/*
+ * Struct prepared for RecordDeepCopyTest.
+ *
+ */
+struct RecordDeepCopyTest : public ::testing::Test {
+
+	struct Dense_record_t {
+		int my_int_array[9];
+		char my_char;
+		long my_long_array[10];
+	};
+	struct Sparse_record_t {
+		int my_int_array[25];
+		char my_char;
+		long my_long_array[100];
+	};
+	int copied_scalar;
+	
+	RecordDeepCopyTest()
+	{
+		for (int i = 0; i < 9; i++) {
+			dense_record.my_int_array[i] = i;
+		}
+		dense_record.my_char = 9;
+		for (int i = 0; i < 10; i++) {
+			dense_record.my_long_array[i] = i + 10;
+		}
+		
+		for (int i = 0; i < 25; i++) {
+			sparse_record.my_int_array[i] = 0;
+		}
+		sparse_record.my_char = 0;
+		for (int i = 0; i < 100; i++) {
+			sparse_record.my_long_array[i] = 0;
+		}
+	}
+	
+	Dense_record_t dense_record;
+	Sparse_record_t sparse_record;
+	
+	Datatype_uptr datatype {
+		new Record_datatype {
+			vector<Record_datatype::Member> {
+				Record_datatype::Member{
+					0,
+					unique_ptr<Datatype> {
+						new Array_datatype
+						{
+							unique_ptr<Datatype> {
+								new Array_datatype
+								{
+									unique_ptr<Datatype>{new Scalar_datatype {Scalar_kind::SIGNED, sizeof(int)}},
+									5,
+									1,
+									3
+								}
+							},
+							5,
+							1,
+							3
+						}
+					},
+					"my_int_array"
+				},
+				Record_datatype::Member{
+					100,
+					unique_ptr<Datatype> { new Scalar_datatype{Scalar_kind::UNSIGNED, sizeof(char)} },
+					"my_char"
+				},
+				Record_datatype::Member{
+					104,
+					unique_ptr<Datatype> {
+						new Array_datatype
+						{
+							unique_ptr<Datatype> {
+								new Array_datatype
+								{
+									unique_ptr<Datatype>{new Scalar_datatype {Scalar_kind::SIGNED, sizeof(long)}},
+									10,
+									2,
+									5
+								}
+							},
+							10,
+							5,
+							2,
+						}
+					},
+					"my_long_array"
+				}
+			},
+			908
+		}
+	};
+	
+};
+
+/*
+ * Name:                RecordDeepCopyTest.dense_to_sparse
+ *
+ * Tested functions:    PDI::ScalarDatatype::data_sparse_copy()
+ *
+ * Description:         Test checks if correct copy is returned
+ *
+ */
+TEST_F(RecordDeepCopyTest, dense_to_sparse)
+{
+	this->datatype->data_from_dense_copy(&this->sparse_record, &this->dense_record);
+	for (int i = 1; i < 4; i++) {
+		for (int j = 1; j < 4; j++) {
+			ASSERT_EQ(this->dense_record.my_int_array[3*(i-1) + j-1], this->sparse_record.my_int_array[i*5 + j]);
+		}
+	}
+	ASSERT_EQ(this->dense_record.my_char, this->sparse_record.my_char);
+	for (int i = 5; i < 7; i++) {
+		for (int j = 2; j < 7; j++) {
+			ASSERT_EQ(this->dense_record.my_long_array[5*(i-5) + j-2], this->sparse_record.my_long_array[i*10 + j]);
+		}
+	}
+}
\ No newline at end of file
diff --git a/tests/PDI_scalar_datatype.cxx b/tests/PDI_scalar_datatype.cxx
index 36fd8cf38bcdd8176998e5c804416a99c6f1d6c7..4b158877f134b9acad97486479da7c9af73cc2ca 100644
--- a/tests/PDI_scalar_datatype.cxx
+++ b/tests/PDI_scalar_datatype.cxx
@@ -191,3 +191,36 @@ TYPED_TEST(ScalarDatatypeTest, check_evaluate)
 	ASSERT_EQ(this->test_scalar->alignment(), cloned_scalar->alignment());
 	ASSERT_EQ(this->test_scalar->dense(), cloned_scalar->dense());
 }
+
+/*
+ * Struct prepared for ScalarDeepCopyTest.
+ *
+ */
+struct ScalarDeepCopyTest : public ::testing::Test {
+
+	int data_scalar;
+	int copied_scalar;
+	
+	ScalarDeepCopyTest()
+	{
+		data_scalar = 123;
+		copied_scalar = 0;
+	}
+	
+	Datatype_uptr datatype {new Scalar_datatype {Scalar_kind::SIGNED, sizeof(int)}};
+	
+};
+
+/*
+ * Name:                ScalarDeepCopyTest.dense_to_sparse
+ *
+ * Tested functions:    PDI::ScalarDatatype::data_sparse_copy()
+ *
+ * Description:         Test checks if correct copy is returned
+ *
+ */
+TEST_F(ScalarDeepCopyTest, dense_to_sparse)
+{
+	this->datatype->data_from_dense_copy(&copied_scalar, &data_scalar);
+	ASSERT_EQ(copied_scalar, data_scalar);
+}
\ No newline at end of file
diff --git a/tests/mocks/datatype_mock.h b/tests/mocks/datatype_mock.h
index 3486fc269bde89d5a90de1a966af463ec2705319..71c8051a18277c71fe01d818cae8221b9c9f8beb 100644
--- a/tests/mocks/datatype_mock.h
+++ b/tests/mocks/datatype_mock.h
@@ -68,7 +68,8 @@ struct MockDatatype : public PDI::Datatype {
 	MOCK_CONST_METHOD0(evaluate_proxy, Datatype*());
 	
 	MOCK_CONST_METHOD0(simple, bool());
-	MOCK_CONST_METHOD2(data_dense_copy, void* (void* to, const void* from));
+	MOCK_CONST_METHOD2(data_to_dense_copy, void* (void* to, const void* from));
+	MOCK_CONST_METHOD2(data_from_dense_copy, void* (void* to, const void* from));
 	MOCK_CONST_METHOD1(destroy_data, void(void* ptr));
 	MOCK_CONST_METHOD1(equals, bool(const Datatype&));
 	MOCK_CONST_METHOD0(debug_string, std::string());