diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index e01ef86..2e675ba 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -90,6 +90,10 @@ typedef struct PartitionBoundInfoData
 								 * for range partitioned tables */
 	int			null_index;		/* Index of the null-accepting partition; -1
 								 * for range partitioned tables */
+	bool		has_def;		/* Is there a default partition? Currently false
+								 * for a range partitioned table */
+	bool		def_index;		/* Index of the default list partition. -1 for
+								 * range partitioned tables */
 } PartitionBoundInfoData;
 
 /*
@@ -166,6 +170,8 @@ RelationBuildPartitionDesc(Relation rel)
 	/* List partitioning specific */
 	PartitionListValue **all_values = NULL;
 	bool		found_null = false;
+	bool		found_def = false;
+	int			def_index = -1;
 	int			null_index = -1;
 
 	/* Range partitioning specific */
@@ -239,6 +245,8 @@ RelationBuildPartitionDesc(Relation rel)
 			i = 0;
 			found_null = false;
 			null_index = -1;
+			found_def = false;
+			def_index = -1;
 			foreach(cell, boundspecs)
 			{
 				ListCell   *c;
@@ -249,6 +257,15 @@ RelationBuildPartitionDesc(Relation rel)
 
 				foreach(c, spec->listdatums)
 				{
+					Node *value = lfirst(c);
+
+					if (IsA(value, DefElem))
+					{
+						found_def = true;
+						def_index = i;
+						continue;
+					}
+
 					Const	   *val = lfirst(c);
 					PartitionListValue *list_value = NULL;
 
@@ -459,6 +476,7 @@ RelationBuildPartitionDesc(Relation rel)
 			case PARTITION_STRATEGY_LIST:
 				{
 					boundinfo->has_null = found_null;
+					boundinfo->has_def = found_def;
 					boundinfo->indexes = (int *) palloc(ndatums * sizeof(int));
 
 					/*
@@ -496,6 +514,11 @@ RelationBuildPartitionDesc(Relation rel)
 						if (mapping[null_index] == -1)
 							mapping[null_index] = next_index++;
 					}
+					if (found_def)
+					{
+						if (mapping[def_index] == -1)
+							mapping[def_index] = next_index++;
+					}
 
 					/* All partition must now have a valid mapping */
 					Assert(next_index == nparts);
@@ -504,6 +527,11 @@ RelationBuildPartitionDesc(Relation rel)
 						boundinfo->null_index = mapping[null_index];
 					else
 						boundinfo->null_index = -1;
+
+					if (found_def)
+						boundinfo->def_index = mapping[def_index];
+					else
+						boundinfo->def_index = -1;
 					break;
 				}
 
@@ -1558,6 +1586,19 @@ generate_partition_qual(Relation rel)
 	bound = stringToNode(TextDatumGetCString(boundDatum));
 	ReleaseSysCache(tuple);
 
+	/* Return if it is a default list partition */
+	PartitionBoundSpec *spec = (PartitionBoundSpec *)bound;
+	ListCell *cell;
+	foreach(cell, spec->listdatums)
+	{
+		Node *value = lfirst(cell);
+		if (IsA(value, DefElem))
+		{
+			/* Keep the parent locked until commit */
+			heap_close(parent, NoLock);
+			return result;
+		}
+	}
 	my_qual = get_qual_from_partbound(rel, parent, bound);
 
 	/* Add the parent's quals to the list (if any) */
@@ -1771,6 +1812,17 @@ get_partition_for_tuple(PartitionDispatch *pd,
 			result = -1;
 			*failed_at = parent;
 			*failed_slot = slot;
+			/*
+			 * If partitioned table has a default partition, return
+			 * its sequence number
+			 */
+			if (partdesc->boundinfo->has_def)
+				result = parent->indexes[partdesc->boundinfo->def_index];
+			else
+			{
+				result = -1;
+				*failed_at = RelationGetRelid(parent->reldesc);
+			}
 			break;
 		}
 		else if (parent->indexes[cur_index] >= 0)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 6316688..ebb7db7 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -2594,6 +2594,7 @@ partbound_datum:
 			Sconst			{ $$ = makeStringConst($1, @1); }
 			| NumericOnly	{ $$ = makeAConst($1, @1); }
 			| NULL_P		{ $$ = makeNullAConst(@1); }
+			| DEFAULT  { $$ = (Node *)makeDefElem("DEFAULT", NULL, @1); }
 		;
 
 partbound_datum_list:
@@ -2601,7 +2602,6 @@ partbound_datum_list:
 			| partbound_datum_list ',' partbound_datum
 												{ $$ = lappend($1, $3); }
 		;
-
 range_datum_list:
 			PartitionRangeDatum					{ $$ = list_make1($1); }
 			| range_datum_list ',' PartitionRangeDatum
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 673276a..ba05ac8 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -3088,47 +3088,50 @@ transformPartitionBound(ParseState *pstate, Relation parent, Node *bound)
 		result_spec->listdatums = NIL;
 		foreach(cell, spec->listdatums)
 		{
-			A_Const    *con = (A_Const *) lfirst(cell);
-			Node	   *value;
-			ListCell   *cell2;
-			bool		duplicate;
-
-			value = (Node *) make_const(pstate, &con->val, con->location);
-			value = coerce_to_target_type(pstate,
-										  value, exprType(value),
-										  get_partition_col_typid(key, 0),
-										  get_partition_col_typmod(key, 0),
-										  COERCION_ASSIGNMENT,
-										  COERCE_IMPLICIT_CAST,
-										  -1);
-
-			if (value == NULL)
-				ereport(ERROR,
-						(errcode(ERRCODE_DATATYPE_MISMATCH),
-						 errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"",
-							 format_type_be(get_partition_col_typid(key, 0)),
-								colname),
-						 parser_errposition(pstate,
-											exprLocation((Node *) con))));
-
-			/* Simplify the expression */
-			value = (Node *) expression_planner((Expr *) value);
-
-			/* Don't add to the result if the value is a duplicate */
-			duplicate = false;
-			foreach(cell2, result_spec->listdatums)
+			Node *value = lfirst(cell);
+			/* Perform the transformation only for non default partition */
+			if (!IsA(value, DefElem))
 			{
-				Const	   *value2 = (Const *) lfirst(cell2);
+				A_Const    *con = (A_Const *) lfirst(cell);
+				ListCell   *cell2;
+				bool		duplicate;
+
+				value = (Node *) make_const(pstate, &con->val, con->location);
+				value = coerce_to_target_type(pstate,
+											value, exprType(value),
+											get_partition_col_typid(key, 0),
+											get_partition_col_typmod(key, 0),
+											COERCION_ASSIGNMENT,
+											COERCE_IMPLICIT_CAST,
+											-1);
+
+				if (value == NULL)
+					ereport(ERROR,
+							(errcode(ERRCODE_DATATYPE_MISMATCH),
+							errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"",
+								format_type_be(get_partition_col_typid(key, 0)),
+									colname),
+							parser_errposition(pstate,
+												exprLocation((Node *) con))));
 
-				if (equal(value, value2))
+				/* Simplify the expression */
+				value = (Node *) expression_planner((Expr *) value);
+
+				/* Don't add to the result if the value is a duplicate */
+				duplicate = false;
+				foreach(cell2, result_spec->listdatums)
 				{
-					duplicate = true;
-					break;
+					Const	   *value2 = (Const *) lfirst(cell2);
+
+					if (equal(value, value2))
+					{
+						duplicate = true;
+						break;
+					}
 				}
+				if (duplicate)
+					continue;
 			}
-			if (duplicate)
-				continue;
-
 			result_spec->listdatums = lappend(result_spec->listdatums,
 											  value);
 		}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 5c82325..ffdf633 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -8487,8 +8487,13 @@ get_rule_expr(Node *node, deparse_context *context,
 						sep = "";
 						foreach(cell, spec->listdatums)
 						{
+							Node *value = lfirst(cell);
 							Const	   *val = lfirst(cell);
-
+							if (IsA(value, DefElem))
+							{
+								appendStringInfoString(buf, "DEFAULT");
+								continue;
+							}
 							appendStringInfoString(buf, sep);
 							get_const_expr(val, context, -1);
 							sep = ", ";
