diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index dbd6094..ea06a57 100644
*** a/src/backend/catalog/heap.c
--- b/src/backend/catalog/heap.c
*************** static void StoreConstraints(Relation re
*** 105,110 ****
--- 105,111 ----
  				 bool is_internal);
  static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
  							bool allow_merge, bool is_local,
+ 							bool is_initially_valid,
  							bool is_no_inherit);
  static void SetRelationNumChecks(Relation rel, int numchecks);
  static Node *cookConstraint(ParseState *pstate,
*************** AddRelationNewConstraints(Relation rel,
*** 2301,2306 ****
--- 2302,2308 ----
  			 */
  			if (MergeWithExistingConstraint(rel, ccname, expr,
  											allow_merge, is_local,
+ 											cdef->initially_valid,
  											cdef->is_no_inherit))
  				continue;
  		}
*************** AddRelationNewConstraints(Relation rel,
*** 2389,2394 ****
--- 2391,2397 ----
  static bool
  MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
  							bool allow_merge, bool is_local,
+ 							bool is_initially_valid,
  							bool is_no_inherit)
  {
  	bool		found;
*************** MergeWithExistingConstraint(Relation rel
*** 2436,2457 ****
  				if (equal(expr, stringToNode(TextDatumGetCString(val))))
  					found = true;
  			}
  			if (!found || !allow_merge)
  				ereport(ERROR,
  						(errcode(ERRCODE_DUPLICATE_OBJECT),
  				errmsg("constraint \"%s\" for relation \"%s\" already exists",
  					   ccname, RelationGetRelationName(rel))));
  
! 			tup = heap_copytuple(tup);
! 			con = (Form_pg_constraint) GETSTRUCT(tup);
! 
! 			/* If the constraint is "no inherit" then cannot merge */
  			if (con->connoinherit)
  				ereport(ERROR,
  						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
  						 errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
  								ccname, RelationGetRelationName(rel))));
  
  			if (is_local)
  				con->conislocal = true;
  			else
--- 2439,2485 ----
  				if (equal(expr, stringToNode(TextDatumGetCString(val))))
  					found = true;
  			}
+ 
+ 			/*
+ 			 * If the existing constraint is purely inherited (no local
+ 			 * definition) then interpret addition of a local constraint as a
+ 			 * legal merge.  This allows ALTER ADD CONSTRAINT on parent and
+ 			 * child tables to be given in either order with same end state.
+ 			 */
+ 			if (is_local && !con->conislocal)
+ 				allow_merge = true;
+ 
  			if (!found || !allow_merge)
  				ereport(ERROR,
  						(errcode(ERRCODE_DUPLICATE_OBJECT),
  				errmsg("constraint \"%s\" for relation \"%s\" already exists",
  					   ccname, RelationGetRelationName(rel))));
  
! 			/* If the child constraint is "no inherit" then cannot merge */
  			if (con->connoinherit)
  				ereport(ERROR,
  						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
  						 errmsg("constraint \"%s\" conflicts with non-inherited constraint on relation \"%s\"",
  								ccname, RelationGetRelationName(rel))));
  
+ 			/*
+ 			 * If the child constraint is "not valid" then cannot merge with a
+ 			 * valid parent constraint
+ 			 */
+ 			if (is_initially_valid && !con->convalidated)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ 						 errmsg("constraint \"%s\" conflicts with NOT VALID constraint on relation \"%s\"",
+ 								ccname, RelationGetRelationName(rel))));
+ 
+ 			/* OK to update the tuple */
+ 			ereport(NOTICE,
+ 			   (errmsg("merging constraint \"%s\" with inherited definition",
+ 					   ccname)));
+ 
+ 			tup = heap_copytuple(tup);
+ 			con = (Form_pg_constraint) GETSTRUCT(tup);
+ 
  			if (is_local)
  				con->conislocal = true;
  			else
*************** MergeWithExistingConstraint(Relation rel
*** 2461,2470 ****
  				Assert(is_local);
  				con->connoinherit = true;
  			}
- 			/* OK to update the tuple */
- 			ereport(NOTICE,
- 			   (errmsg("merging constraint \"%s\" with inherited definition",
- 					   ccname)));
  			simple_heap_update(conDesc, &tup->t_self, tup);
  			CatalogUpdateIndexes(conDesc, tup);
  			break;
--- 2489,2494 ----
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d312762..f822ed9 100644
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
*************** MergeConstraintsIntoExisting(Relation ch
*** 10373,10379 ****
  								RelationGetRelationName(child_rel),
  								NameStr(parent_con->conname))));
  
! 			/* If the constraint is "no inherit" then cannot merge */
  			if (child_con->connoinherit)
  				ereport(ERROR,
  						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
--- 10373,10379 ----
  								RelationGetRelationName(child_rel),
  								NameStr(parent_con->conname))));
  
! 			/* If the child constraint is "no inherit" then cannot merge */
  			if (child_con->connoinherit)
  				ereport(ERROR,
  						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
*************** MergeConstraintsIntoExisting(Relation ch
*** 10382,10387 ****
--- 10382,10398 ----
  								RelationGetRelationName(child_rel))));
  
  			/*
+ 			 * If the child constraint is "not valid" then cannot merge with a
+ 			 * valid parent constraint
+ 			 */
+ 			if (parent_con->convalidated && !child_con->convalidated)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ 						 errmsg("constraint \"%s\" conflicts with NOT VALID constraint on child table \"%s\"",
+ 								NameStr(child_con->conname),
+ 								RelationGetRelationName(child_rel))));
+ 
+ 			/*
  			 * OK, bump the child constraint's inheritance count.  (If we fail
  			 * later on, this change will just roll back.)
  			 */
