diff --git a/src/mock/MetaCache.cpp b/src/mock/MetaCache.cpp
index 05f390428e8e4ded0ba64c54ca9da7924e8dfda9..11cd3e4fd44bdb3763edc9da40ffff373694b579 100644
--- a/src/mock/MetaCache.cpp
+++ b/src/mock/MetaCache.cpp
@@ -785,9 +785,9 @@ Status MetaCache::alterSchemaProp(meta::cpp2::Schema &schema,
         for (auto& col : schema.columns) {
             if (col.get_name() == ttlCol) {
                 // Only integer and timestamp columns can be used as ttl_col
-                if (col.type != meta::cpp2::PropertyType::INT32 &&
-                    col.type != meta::cpp2::PropertyType::INT64 &&
-                    col.type != meta::cpp2::PropertyType::TIMESTAMP) {
+                if (col.type.type != meta::cpp2::PropertyType::INT32 &&
+                    col.type.type != meta::cpp2::PropertyType::INT64 &&
+                    col.type.type != meta::cpp2::PropertyType::TIMESTAMP) {
                     return Status::Error("TTL column type illegal");
                 }
                 existed = true;
diff --git a/src/mock/test/TestMock.cpp b/src/mock/test/TestMock.cpp
index 5c0ffdaac65fcf755e42a6f1f0b8eda3a6e1dfa5..34c7c812e0e901613b941df37e0ff298dc91660c 100644
--- a/src/mock/test/TestMock.cpp
+++ b/src/mock/test/TestMock.cpp
@@ -84,7 +84,7 @@ TEST_F(MockServerTest, TestMeta) {
             meta::cpp2::Schema tagSchema;
             meta::cpp2::ColumnDef col;
             col.set_name(folly::stringPrintf("col_%d", i));
-            col.set_type(meta::cpp2::PropertyType::STRING);
+            col.type.set_type(meta::cpp2::PropertyType::STRING);
             col.set_default_value(nebula::Value("NULL"));
             std::vector<meta::cpp2::ColumnDef> cols;
             cols.emplace_back(col);
@@ -102,7 +102,8 @@ TEST_F(MockServerTest, TestMeta) {
             auto schema = status.value();
             ASSERT_EQ(1, schema.get_columns().size());
             ASSERT_EQ(folly::stringPrintf("col_%d", i), schema.get_columns()[0].get_name());
-            ASSERT_EQ(meta::cpp2::PropertyType::STRING, schema.get_columns()[0].get_type());
+            ASSERT_EQ(meta::cpp2::PropertyType::STRING,
+                      schema.get_columns()[0].get_type().get_type());
             ASSERT_EQ("NULL", schema.get_columns()[0].get_default_value()->getStr());
         }
 
@@ -131,7 +132,9 @@ TEST_F(MockServerTest, TestMeta) {
             meta::cpp2::Schema edgeSchema;
             meta::cpp2::ColumnDef col;
             col.set_name(folly::stringPrintf("col_%d", i));
-            col.set_type(meta::cpp2::PropertyType::STRING);
+            meta::cpp2::ColumnTypeDef typeDef;
+            typeDef.set_type(meta::cpp2::PropertyType::STRING);
+            col.set_type(std::move(typeDef));
             col.set_default_value(nebula::Value("NULL"));
             std::vector<meta::cpp2::ColumnDef> cols;
             cols.emplace_back(col);
@@ -149,7 +152,8 @@ TEST_F(MockServerTest, TestMeta) {
             auto schema = status.value();
             ASSERT_EQ(1, schema.get_columns().size());
             ASSERT_EQ(folly::stringPrintf("col_%d", i), schema.get_columns()[0].get_name());
-            ASSERT_EQ(meta::cpp2::PropertyType::STRING, schema.get_columns()[0].get_type());
+            ASSERT_EQ(meta::cpp2::PropertyType::STRING,
+                      schema.get_columns()[0].get_type().get_type());
             ASSERT_EQ("NULL", schema.get_columns()[0].get_default_value()->getStr());
         }
 
diff --git a/src/optimizer/OptimizerUtils.cpp b/src/optimizer/OptimizerUtils.cpp
index 93394ed0930e5a5ce19866130322ff45668fd89a..7f261c1604d943679746ac71607c8787a841f59b 100644
--- a/src/optimizer/OptimizerUtils.cpp
+++ b/src/optimizer/OptimizerUtils.cpp
@@ -30,7 +30,7 @@ Value OptimizerUtils::boundValue(const meta::cpp2::ColumnDef& col,
 }
 
 Value OptimizerUtils::boundValueWithGT(const meta::cpp2::ColumnDef& col, const Value& v) {
-    auto type = SchemaUtil::propTypeToValueType(col.get_type());
+    auto type = SchemaUtil::propTypeToValueType(col.get_type().get_type());
     switch (type) {
         case Value::Type::INT : {
             if (v.getInt() == std::numeric_limits<int64_t>::max()) {
@@ -57,16 +57,17 @@ Value OptimizerUtils::boundValueWithGT(const meta::cpp2::ColumnDef& col, const V
             return v;
         }
         case Value::Type::STRING : {
-            if (!col.__isset.type_length || col.get_type_length() == nullptr) {
+            if (!col.type.__isset.type_length ||
+                col.get_type().get_type_length() == nullptr) {
                 return Value(NullType::BAD_TYPE);
             }
             std::vector<unsigned char> bytes(v.getStr().begin(), v.getStr().end());
-            bytes.resize(*col.get_type_length());
+            bytes.resize(*col.get_type().get_type_length());
             for (size_t i = bytes.size();; i--) {
                 if (i > 0) {
                     if (bytes[i-1]++ != 255) break;
                 } else {
-                    return Value(std::string(*col.get_type_length(), '\377'));
+                    return Value(std::string(*col.get_type().get_type_length(), '\377'));
                 }
             }
             return Value(std::string(bytes.begin(), bytes.end()));
@@ -179,7 +180,7 @@ Value OptimizerUtils::boundValueWithGT(const meta::cpp2::ColumnDef& col, const V
 }
 
 Value OptimizerUtils::boundValueWithLT(const meta::cpp2::ColumnDef& col, const Value& v) {
-    auto type = SchemaUtil::propTypeToValueType(col.get_type());
+    auto type = SchemaUtil::propTypeToValueType(col.get_type().get_type());
     switch (type) {
         case Value::Type::INT : {
             if (v.getInt() == std::numeric_limits<int64_t>::min()) {
@@ -204,16 +205,16 @@ Value OptimizerUtils::boundValueWithLT(const meta::cpp2::ColumnDef& col, const V
             return v;
         }
         case Value::Type::STRING : {
-            if (!col.__isset.type_length || col.get_type_length() == nullptr) {
+            if (!col.type.__isset.type_length || col.get_type().get_type_length() == nullptr) {
                 return Value(NullType::BAD_TYPE);
             }
             std::vector<unsigned char> bytes(v.getStr().begin(), v.getStr().end());
-            bytes.resize(*col.get_type_length());
+            bytes.resize(*col.get_type().get_type_length());
             for (size_t i = bytes.size();; i--) {
                 if (i > 0) {
                     if (bytes[i-1]-- != 0) break;
                 } else {
-                    return Value(std::string(*col.get_type_length(), '\0'));
+                    return Value(std::string(*col.get_type().get_type_length(), '\0'));
                 }
             }
             return Value(std::string(bytes.begin(), bytes.end()));
@@ -328,7 +329,7 @@ Value OptimizerUtils::boundValueWithLT(const meta::cpp2::ColumnDef& col, const V
 }
 
 Value OptimizerUtils::boundValueWithMax(const meta::cpp2::ColumnDef& col, const Value& v) {
-    auto type = SchemaUtil::propTypeToValueType(col.get_type());
+    auto type = SchemaUtil::propTypeToValueType(col.get_type().get_type());
     switch (type) {
         case Value::Type::INT : {
             return Value(std::numeric_limits<int64_t>::max());
@@ -340,10 +341,11 @@ Value OptimizerUtils::boundValueWithMax(const meta::cpp2::ColumnDef& col, const
             return v;
         }
         case Value::Type::STRING : {
-            if (!col.__isset.type_length || col.get_type_length() == nullptr) {
+            if (!col.type.__isset.type_length ||
+                col.get_type().get_type_length() == nullptr) {
                 return Value(NullType::BAD_TYPE);
             }
-            return Value(std::string(*col.get_type_length(), '\377'));
+            return Value(std::string(*col.get_type().get_type_length(), '\377'));
         }
         case Value::Type::DATE : {
             Date d;
@@ -390,7 +392,7 @@ Value OptimizerUtils::boundValueWithMax(const meta::cpp2::ColumnDef& col, const
 }
 
 Value OptimizerUtils::boundValueWithMin(const meta::cpp2::ColumnDef& col, const Value& v) {
-    auto type = SchemaUtil::propTypeToValueType(col.get_type());
+    auto type = SchemaUtil::propTypeToValueType(col.get_type().get_type());
     switch (type) {
         case Value::Type::INT : {
             return Value(std::numeric_limits<int64_t>::min());
@@ -402,10 +404,11 @@ Value OptimizerUtils::boundValueWithMin(const meta::cpp2::ColumnDef& col, const
             return v;
         }
         case Value::Type::STRING : {
-            if (!col.__isset.type_length || col.get_type_length() == nullptr) {
+            if (!col.type.__isset.type_length ||
+                col.get_type().get_type_length() == nullptr) {
                 return Value(NullType::BAD_TYPE);
             }
-            return Value(std::string(*col.get_type_length(), '\0'));
+            return Value(std::string(*col.get_type().get_type_length(), '\0'));
         }
         case Value::Type::DATE : {
             return Value(Date());
diff --git a/src/optimizer/test/IndexBoundValueTest.cpp b/src/optimizer/test/IndexBoundValueTest.cpp
index bec1746bfcc0279e2d88ecf0403718a88f042aa5..810c502d5c319620768ecf2b76845872bb2c485d 100644
--- a/src/optimizer/test/IndexBoundValueTest.cpp
+++ b/src/optimizer/test/IndexBoundValueTest.cpp
@@ -15,8 +15,10 @@ using OP = OptimizerUtils::BoundValueOperator;
 TEST(IndexBoundValueTest, StringTest) {
     meta::cpp2::ColumnDef col;
     {
-        col.set_type(meta::cpp2::PropertyType::FIXED_STRING);
-        col.set_type_length(8);
+        meta::cpp2::ColumnTypeDef typeDef;
+        typeDef.set_type(meta::cpp2::PropertyType::FIXED_STRING);
+        typeDef.set_type_length(8);
+        col.set_type(std::move(typeDef));
     }
     std::vector<unsigned char> max = {255, 255, 255, 255, 255, 255, 255, 255};
     std::vector<unsigned char> min = {'\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0'};
@@ -72,7 +74,9 @@ TEST(IndexBoundValueTest, StringTest) {
 TEST(IndexBoundValueTest, BoolTest) {
     meta::cpp2::ColumnDef col;
     {
-        col.set_type(meta::cpp2::PropertyType::BOOL);
+        meta::cpp2::ColumnTypeDef typeDef;
+        typeDef.set_type(meta::cpp2::PropertyType::BOOL);
+        col.set_type(std::move(typeDef));
     }
     EXPECT_TRUE(OptimizerUtils::boundValue(col, OP::MIN, Value(true)).getBool());
     EXPECT_TRUE(OptimizerUtils::boundValue(col, OP::MAX, Value(true)).getBool());
@@ -94,7 +98,9 @@ TEST(IndexBoundValueTest, BoolTest) {
 TEST(IndexBoundValueTest, IntTest) {
     meta::cpp2::ColumnDef col;
     {
-        col.set_type(meta::cpp2::PropertyType::INT64);
+        meta::cpp2::ColumnTypeDef typeDef;
+        typeDef.set_type(meta::cpp2::PropertyType::INT64);
+        col.set_type(std::move(typeDef));
     }
     auto maxInt = std::numeric_limits<int64_t>::max();
     auto minInt = std::numeric_limits<int64_t>::min();
@@ -120,7 +126,9 @@ TEST(IndexBoundValueTest, IntTest) {
 TEST(IndexBoundValueTest, DoubleTest) {
     meta::cpp2::ColumnDef col;
     {
-        col.set_type(meta::cpp2::PropertyType::DOUBLE);
+        meta::cpp2::ColumnTypeDef typeDef;
+        typeDef.set_type(meta::cpp2::PropertyType::DOUBLE);
+        col.set_type(std::move(typeDef));
     }
     auto maxDouble = std::numeric_limits<double_t>::max();
     auto minDouble = std::numeric_limits<double_t>::min();
@@ -158,7 +166,9 @@ TEST(IndexBoundValueTest, DoubleTest) {
 TEST(IndexBoundValueTest, DateTest) {
     meta::cpp2::ColumnDef col;
     {
-        col.set_type(meta::cpp2::PropertyType::DATE);
+        meta::cpp2::ColumnTypeDef typeDef;
+        typeDef.set_type(meta::cpp2::PropertyType::DATE);
+        col.set_type(std::move(typeDef));
     }
     auto maxYear = std::numeric_limits<int16_t>::max();
     EXPECT_EQ(Date(maxYear, 12, 31),
@@ -182,7 +192,9 @@ TEST(IndexBoundValueTest, DateTest) {
 TEST(IndexBoundValueTest, DateTimeTest) {
     meta::cpp2::ColumnDef col;
     {
-        col.set_type(meta::cpp2::PropertyType::DATETIME);
+        meta::cpp2::ColumnTypeDef typeDef;
+        typeDef.set_type(meta::cpp2::PropertyType::DATETIME);
+        col.set_type(std::move(typeDef));
     }
     DateTime maxDT;
     {
diff --git a/src/util/SchemaUtil.cpp b/src/util/SchemaUtil.cpp
index 93f55422e24d8318a5a86b4da678f0e8ccce6dd5..381e3088dbee3647335c47303df84fb65feb99e5 100644
--- a/src/util/SchemaUtil.cpp
+++ b/src/util/SchemaUtil.cpp
@@ -23,12 +23,14 @@ Status SchemaUtil::validateColumns(const std::vector<ColumnSpecification*> &colu
         }
         nameSet.emplace(*spec->name());
         meta::cpp2::ColumnDef column;
-        auto type = spec->type();
         column.set_name(*spec->name());
-        column.set_type(type);
+        auto type = spec->type();
+        meta::cpp2::ColumnTypeDef typeDef;
+        typeDef.set_type(type);
+        column.set_type(std::move(typeDef));
         column.set_nullable(spec->isNull());
         if (meta::cpp2::PropertyType::FIXED_STRING == type) {
-            column.set_type_length(spec->typeLen());
+            column.type.set_type_length(spec->typeLen());
         }
 
         if (spec->hasDefaultValue()) {
@@ -87,8 +89,8 @@ SchemaUtil::generateSchemaProvider(const SchemaVer ver, const meta::cpp2::Schema
     for (auto col : schema.get_columns()) {
         bool hasDef = col.__isset.default_value;
         schemaPtr->addField(col.get_name(),
-                            col.get_type(),
-                            col.__isset.type_length ? *col.get_type_length() : 0,
+                            col.get_type().get_type(),
+                            col.type.__isset.type_length ? *col.get_type().get_type_length() : 0,
                             col.__isset.nullable ? *col.get_nullable() : false,
                             hasDef ? *col.get_default_value() : Value());
     }
@@ -175,8 +177,8 @@ Status SchemaUtil::setTTLCol(SchemaPropItem* schemaProp, meta::cpp2::Schema& sch
         if (col.name == ttlColName) {
             // Only integer columns and timestamp columns can be used as ttl_col
             // TODO(YT) Ttl_duration supports datetime type
-            if (col.type != meta::cpp2::PropertyType::INT64 &&
-                col.type != meta::cpp2::PropertyType::TIMESTAMP) {
+            if (col.type.type != meta::cpp2::PropertyType::INT64 &&
+                col.type.type != meta::cpp2::PropertyType::TIMESTAMP) {
                 return Status::Error("Ttl column type illegal");
             }
             schema.schema_prop.set_ttl_col(ttlColName);
@@ -289,7 +291,7 @@ StatusOr<DataSet> SchemaUtil::toShowCreateSchema(bool isTag,
 }
 
 std::string SchemaUtil::typeToString(const meta::cpp2::ColumnDef &col) {
-    switch (col.get_type()) {
+    switch (col.get_type().get_type()) {
         case meta::cpp2::PropertyType::BOOL:
             return "bool";
         case meta::cpp2::PropertyType::INT8:
@@ -309,7 +311,7 @@ std::string SchemaUtil::typeToString(const meta::cpp2::ColumnDef &col) {
         case meta::cpp2::PropertyType::STRING:
             return "string";
         case meta::cpp2::PropertyType::FIXED_STRING: {
-            auto typeLen = col.__isset.type_length ? *col.get_type_length() : 0;
+            auto typeLen = col.type.__isset.type_length ? *col.get_type().get_type_length() : 0;
             return folly::stringPrintf("fixed_string(%d)", typeLen);
         }
         case meta::cpp2::PropertyType::TIMESTAMP:
diff --git a/src/util/ToJson.cpp b/src/util/ToJson.cpp
index 2c180dacd6ca96c358dc7d753eef613fe6478dcf..4a78ed61d05bf9c6bab34c1a31085a5b2dab562d 100644
--- a/src/util/ToJson.cpp
+++ b/src/util/ToJson.cpp
@@ -67,9 +67,9 @@ folly::dynamic toJson(const meta::cpp2::SpaceDesc &desc) {
 folly::dynamic toJson(const meta::cpp2::ColumnDef &column) {
     folly::dynamic obj = folly::dynamic::object();
     obj.insert("name", column.get_name());
-    obj.insert("type", meta::cpp2::_PropertyType_VALUES_TO_NAMES.at(column.get_type()));
-    if (column.__isset.type_length) {
-        obj.insert("typeLength", folly::to<std::string>(*column.get_type_length()));
+    obj.insert("type", meta::cpp2::_PropertyType_VALUES_TO_NAMES.at(column.get_type().get_type()));
+    if (column.type.__isset.type_length) {
+        obj.insert("typeLength", folly::to<std::string>(*column.get_type().get_type_length()));
     }
     if (column.__isset.nullable) {
         obj.insert("nullable", folly::to<std::string>(*column.get_nullable()));
diff --git a/src/validator/MaintainValidator.cpp b/src/validator/MaintainValidator.cpp
index a6599bf3a4d77606c57d5a2f857d926b4c30c691..af10e4732f099a681afbeb744bf09ce1dd8484c6 100644
--- a/src/validator/MaintainValidator.cpp
+++ b/src/validator/MaintainValidator.cpp
@@ -147,12 +147,14 @@ Status AlterValidator::alterSchema(const std::vector<AlterSchemaOptItem*>& schem
                 for (auto& spec : specs) {
                     meta::cpp2::ColumnDef column;
                     column.name = *spec->name();
-                    column.type = spec->type();
+                    meta::cpp2::ColumnTypeDef typeDef;
+                    typeDef.set_type(spec->type());
+                    column.type = typeDef;
                     if (spec->hasDefaultValue()) {
                         column.set_default_value(spec->getDefaultValue());
                     }
                     if (spec->type() == meta::cpp2::PropertyType::FIXED_STRING) {
-                        column.set_type_length(spec->typeLen());
+                        column.type.set_type_length(spec->typeLen());
                     }
                     if (spec->isNull()) {
                         column.set_nullable(true);