*** a/src/backend/parser/analyze.c
--- b/src/backend/parser/analyze.c
***************
*** 42,47 ****
--- 42,49 ----
  #include "parser/parse_target.h"
  #include "parser/parsetree.h"
  #include "rewrite/rewriteManip.h"
+ #include "utils/builtins.h"
+ #include "utils/lsyscache.h"
  #include "utils/rel.h"
  
  
***************
*** 1796,1801 **** transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
--- 1798,1804 ----
  						  bool isTopLevel, List **targetlist)
  {
  	bool		isLeaf;
+ 	int			varattno;
  
  	Assert(stmt && IsA(stmt, SelectStmt));
  
***************
*** 1980,1985 **** transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
--- 1983,1989 ----
  		op->colTypmods = NIL;
  		op->colCollations = NIL;
  		op->groupClauses = NIL;
+ 		varattno = 0;
  		forboth(ltl, ltargetlist, rtl, rtargetlist)
  		{
  			TargetEntry *ltle = (TargetEntry *) lfirst(ltl);
***************
*** 2008,2013 **** transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
--- 2012,2019 ----
  			else
  				rescoltypmod = -1;
  
+ 			varattno++;
+ 
  			/*
  			 * Verify the coercions are actually possible.  If not, we'd fail
  			 * later anyway, but we want to fail now while we have sufficient
***************
*** 2110,2115 **** transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
--- 2116,2161 ----
  			}
  
  			/*
+ 			 * Verify that the previously determined output column types and
+ 			 * collations match what the query really produced.  We have to
+ 			 * check this because the recursive term could have overridden the
+ 			 * non-recursive term, and we don't have any easy way to fix that.
+ 			 */
+ 			if (isTopLevel &&
+ 				pstate->p_parent_cte &&
+ 				pstate->p_parent_cte->cterecursive)
+ 			{
+ 				Oid	lcolcoll = exprCollation((Node *)ltle->expr);
+ 
+ 				/*
+ 				 * This might somewhat confusing but we suggest to fix
+ 				 * recursive term since non-recursive term may have the same
+ 				 * type without typemod.
+ 				 */
+ 				if (rescoltype != lcoltype || rescoltypmod != lcoltypmod)
+ 					ereport(ERROR,
+ 							(errcode(ERRCODE_DATATYPE_MISMATCH),
+ 							 errmsg("recursive query \"%s\" column %d has type %s in non-recursive term but type %s overall",
+ 									pstate->p_parent_cte->ctename, varattno,
+ 									format_type_with_typemod(lcoltype,
+ 															 lcoltypmod),
+ 									format_type_with_typemod(rescoltype,
+ 															 rescoltypmod)),
+ 							 errhint("Cast the output of the recursive term to the type of the non-recursive term."),
+ 							 parser_errposition(pstate,
+ 												exprLocation((Node *)rtle->expr))));
+ 				if (rescolcoll != lcolcoll)
+ 					ereport(ERROR,
+ 							(errcode(ERRCODE_COLLATION_MISMATCH),
+ 							 errmsg("recursive query \"%s\" column %d has collation \"%s\" in non-recursive term but collation \"%s\" overall",
+ 									pstate->p_parent_cte->ctename, varattno,
+ 									get_collation_name(lcolcoll),
+ 									get_collation_name(rescolcoll)),
+ 						 errhint("Use the COLLATE clause to set the collation of the non-recursive term."),
+ 							 parser_errposition(pstate, exprLocation((Node *)ltle->expr))));
+ 			}
+ 
+ 			/*
  			 * Construct a dummy tlist entry to return.  We use a SetToDefault
  			 * node for the expression, since it carries exactly the fields
  			 * needed, but any other expression node type would do as well.
*** a/src/backend/parser/parse_cte.c
--- b/src/backend/parser/parse_cte.c
***************
*** 276,339 **** analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
  		/* Compute the output column names/types if not done yet */
  		analyzeCTETargetList(pstate, cte, GetCTETargetList(cte));
  	}
! 	else
! 	{
! 		/*
! 		 * Verify that the previously determined output column types and
! 		 * collations match what the query really produced.  We have to check
! 		 * this because the recursive term could have overridden the
! 		 * non-recursive term, and we don't have any easy way to fix that.
! 		 */
! 		ListCell   *lctlist,
! 				   *lctyp,
! 				   *lctypmod,
! 				   *lccoll;
! 		int			varattno;
! 
! 		lctyp = list_head(cte->ctecoltypes);
! 		lctypmod = list_head(cte->ctecoltypmods);
! 		lccoll = list_head(cte->ctecolcollations);
! 		varattno = 0;
! 		foreach(lctlist, GetCTETargetList(cte))
! 		{
! 			TargetEntry *te = (TargetEntry *) lfirst(lctlist);
! 			Node	   *texpr;
! 
! 			if (te->resjunk)
! 				continue;
! 			varattno++;
! 			Assert(varattno == te->resno);
! 			if (lctyp == NULL || lctypmod == NULL || lccoll == NULL)	/* shouldn't happen */
! 				elog(ERROR, "wrong number of output columns in WITH");
! 			texpr = (Node *) te->expr;
! 			if (exprType(texpr) != lfirst_oid(lctyp) ||
! 				exprTypmod(texpr) != lfirst_int(lctypmod))
! 				ereport(ERROR,
! 						(errcode(ERRCODE_DATATYPE_MISMATCH),
! 						 errmsg("recursive query \"%s\" column %d has type %s in non-recursive term but type %s overall",
! 								cte->ctename, varattno,
! 								format_type_with_typemod(lfirst_oid(lctyp),
! 														 lfirst_int(lctypmod)),
! 								format_type_with_typemod(exprType(texpr),
! 														 exprTypmod(texpr))),
! 						 errhint("Cast the output of the non-recursive term to the correct type."),
! 						 parser_errposition(pstate, exprLocation(texpr))));
! 			if (exprCollation(texpr) != lfirst_oid(lccoll))
! 				ereport(ERROR,
! 						(errcode(ERRCODE_COLLATION_MISMATCH),
! 						 errmsg("recursive query \"%s\" column %d has collation \"%s\" in non-recursive term but collation \"%s\" overall",
! 								cte->ctename, varattno,
! 								get_collation_name(lfirst_oid(lccoll)),
! 								get_collation_name(exprCollation(texpr))),
! 						 errhint("Use the COLLATE clause to set the collation of the non-recursive term."),
! 						 parser_errposition(pstate, exprLocation(texpr))));
! 			lctyp = lnext(lctyp);
! 			lctypmod = lnext(lctypmod);
! 			lccoll = lnext(lccoll);
! 		}
! 		if (lctyp != NULL || lctypmod != NULL || lccoll != NULL)	/* shouldn't happen */
! 			elog(ERROR, "wrong number of output columns in WITH");
! 	}
  }
  
  /*
--- 276,286 ----
  		/* Compute the output column names/types if not done yet */
  		analyzeCTETargetList(pstate, cte, GetCTETargetList(cte));
  	}
! 	/*
! 	 * For the recursive cte case, the previously determined output column
! 	 * types and collations are known to match what the query really
! 	 * produced. See transformSetOperationStmtTree.
! 	 */
  }
  
  /*
