diff --git a/src/ir/relation.rs b/src/ir/relation.rs
index 4a3ae7ca55d2f4f29d73ed406ea586ae0d19d258..462f8a4fe2d5885702fcd4d709d0a68128dbc074 100644
--- a/src/ir/relation.rs
+++ b/src/ir/relation.rs
@@ -1,14 +1,16 @@
 //! Relation module.
 
 use std::collections::{HashMap, HashSet};
+use std::fmt::Formatter;
 
-use super::distribution::Key;
+use serde::{Deserialize, Deserializer, Serialize};
+use serde::de::{Error, MapAccess, Visitor};
 use serde::ser::{Serialize as SerSerialize, SerializeMap, Serializer};
-use serde::{Deserialize, Serialize};
 use tarantool::hlua::{self, LuaRead};
 
 use crate::errors::QueryPlannerError;
 
+use super::distribution::Key;
 use super::value::Value;
 
 /// Supported column types.
@@ -39,7 +41,7 @@ impl Type {
 }
 
 /// Relation column.
-#[derive(LuaRead, Deserialize, PartialEq, Debug, Eq, Clone)]
+#[derive(LuaRead, PartialEq, Debug, Eq, Clone)]
 pub struct Column {
     /// Column name.
     pub name: String,
@@ -50,8 +52,8 @@ pub struct Column {
 /// Msgpack serializer for column
 impl SerSerialize for Column {
     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
-    where
-        S: Serializer,
+        where
+            S: Serializer,
     {
         let mut map = serializer.serialize_map(Some(2))?;
         map.serialize_entry("name", &self.name)?;
@@ -67,6 +69,46 @@ impl SerSerialize for Column {
     }
 }
 
+struct ColumnVisitor;
+
+impl<'de> Visitor<'de> for ColumnVisitor {
+    type Value = Column;
+
+    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
+        formatter.write_str("column parsing failed")
+    }
+
+    fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error> where A: MapAccess<'de> {
+        let mut column_name = String::new();
+        let mut column_type = String::new();
+        while let Some((key, value)) = map.next_entry::<String, String>()? {
+            match key.as_str() {
+                "name" => column_name.push_str(&value),
+                "type" => column_type.push_str(&value.to_lowercase()),
+                _ => return Err(Error::custom("invalid column param"))
+            }
+        }
+
+        match column_type.as_str() {
+            "boolean" => Ok(Column::new(&column_name, Type::Boolean)),
+            "number" => Ok(Column::new(&column_name, Type::Number)),
+            "string" => Ok(Column::new(&column_name, Type::String)),
+            "integer" => Ok(Column::new(&column_name, Type::Integer)),
+            "unsigned" => Ok(Column::new(&column_name, Type::Unsigned)),
+            _ => Err(Error::custom("unsupported column type")),
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for Column {
+    fn deserialize<D>(deserializer: D) -> Result<Column, D::Error>
+        where
+            D: Deserializer<'de>,
+    {
+        deserializer.deserialize_map(ColumnVisitor)
+    }
+}
+
 impl Column {
     /// Column constructor.
     #[must_use]
diff --git a/src/ir/relation/tests.rs b/src/ir/relation/tests.rs
index 9f7e4052580129caef6e8b840b53bb1436283318..5647457c0d08ad9901c4630b59b93143168836a5 100644
--- a/src/ir/relation/tests.rs
+++ b/src/ir/relation/tests.rs
@@ -28,7 +28,7 @@ fn table_seg() {
         ],
         &["b", "a"],
     )
-    .unwrap();
+        .unwrap();
     if let Table::Segment { key, .. } = &t {
         assert_eq!(2, key.positions.len());
         assert_eq!(0, key.positions[1]);
@@ -55,7 +55,7 @@ fn table_seg_duplicate_columns() {
             ],
             &["b", "a"],
         )
-        .unwrap_err(),
+            .unwrap_err(),
         QueryPlannerError::DuplicateColumn
     );
 }
@@ -73,7 +73,7 @@ fn table_seg_wrong_key() {
             ],
             &["a", "e"],
         )
-        .unwrap_err(),
+            .unwrap_err(),
         QueryPlannerError::InvalidShardingKey
     );
 }
@@ -92,7 +92,7 @@ fn table_seg_serialized() {
         ],
         &["a", "d"],
     )
-    .unwrap();
+        .unwrap();
     let path = Path::new("")
         .join("tests")
         .join("artifactory")
@@ -185,7 +185,7 @@ fn column_msgpack_serialize() {
     assert_eq!(
         vec![
             0x82, 0xA4, 0x6E, 0x61, 0x6D, 0x65, 0xA4, 0x6E, 0x61, 0x6D, 0x65, 0xA4, 0x74, 0x79,
-            0x70, 0x65, 0xA6, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67
+            0x70, 0x65, 0xA6, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67,
         ],
         rmp_serde::to_vec(&c).unwrap()
     );
@@ -229,3 +229,21 @@ fn column_msgpack_serialize() {
         rmp_serde::to_vec(&c).unwrap()
     )
 }
+
+#[test]
+fn table_converting() {
+    let t = Table::new_seg(
+        "t",
+        vec![
+            Column::new("a", Type::Boolean),
+            Column::new("b", Type::Number),
+            Column::new("c", Type::String),
+            Column::new("d", Type::String),
+        ],
+        &["b", "a"],
+    )
+        .unwrap();
+
+    let s = serde_yaml::to_string(&t).unwrap();
+    Table::seg_from_yaml(&s).unwrap();
+}
\ No newline at end of file