diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index b946a6416a0..75244b4b64e 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -8373,7 +8373,7 @@ select * from rem1;
 create table gloc1 (
   a int,
   b int generated always as (a * 2) stored,
-  c int
+  c int generated always as (a * 3) virtual
 );
 alter table gloc1 set (autovacuum_enabled = 'false');
 create foreign table grem1 (
@@ -8406,10 +8406,10 @@ update grem1 set a = 22 where a = 2;
 
 update grem1 set a = 22 where a = 2;
 select * from gloc1;
- a  | b  | c 
-----+----+---
-  1 |  2 |  
- 22 | 44 |  
+ a  | b  | c  
+----+----+----
+  1 |  2 |  3
+ 22 | 44 | 66
 (2 rows)
 
 select * from grem1;
@@ -8425,8 +8425,8 @@ copy grem1 from stdin;
 select * from gloc1;
  a | b | c 
 ---+---+---
- 1 | 2 |  
- 2 | 4 |  
+ 1 | 2 | 3
+ 2 | 4 | 6
 (2 rows)
 
 select * from grem1;
@@ -8454,8 +8454,8 @@ insert into grem1 (a) values (1), (2);
 select * from gloc1;
  a | b | c 
 ---+---+---
- 1 | 2 |  
- 2 | 4 |  
+ 1 | 2 | 3
+ 2 | 4 | 6
 (2 rows)
 
 select * from grem1;
@@ -10802,7 +10802,7 @@ CREATE TABLE import_source.t3 (c1 timestamptz default now(), c2 typ1);
 CREATE TABLE import_source."x 4" (c1 float8, "C 2" text, c3 varchar(42));
 CREATE TABLE import_source."x 5" (c1 float8);
 ALTER TABLE import_source."x 5" DROP COLUMN c1;
-CREATE TABLE import_source."x 6" (c1 int, c2 int generated always as (c1 * 2) stored);
+CREATE TABLE import_source."x 6" (c1 int, c2 int generated always as (c1 * 2) stored, c3 int generated always as (c1 * 3) virtual);
 CREATE TABLE import_source.t4 (c1 int) PARTITION BY RANGE (c1);
 CREATE TABLE import_source.t4_part PARTITION OF import_source.t4
   FOR VALUES FROM (1) TO (100);
@@ -10876,6 +10876,7 @@ FDW options: (schema_name 'import_source', table_name 'x 5')
 --------+---------+-----------+----------+-------------------------------------+--------------------
  c1     | integer |           |          |                                     | (column_name 'c1')
  c2     | integer |           |          | generated always as (c1 * 2) stored | (column_name 'c2')
+ c3     | integer |           |          | generated always as (c1 * 3)        | (column_name 'c3')
 Server: loopback
 FDW options: (schema_name 'import_source', table_name 'x 6')
 
@@ -10949,6 +10950,7 @@ FDW options: (schema_name 'import_source', table_name 'x 5')
 --------+---------+-----------+----------+-------------------------------------+--------------------
  c1     | integer |           |          |                                     | (column_name 'c1')
  c2     | integer |           |          | generated always as (c1 * 2) stored | (column_name 'c2')
+ c3     | integer |           |          | generated always as (c1 * 3)        | (column_name 'c3')
 Server: loopback
 FDW options: (schema_name 'import_source', table_name 'x 6')
 
@@ -11021,6 +11023,7 @@ FDW options: (schema_name 'import_source', table_name 'x 5')
 --------+---------+-----------+----------+---------+--------------------
  c1     | integer |           |          |         | (column_name 'c1')
  c2     | integer |           |          |         | (column_name 'c2')
+ c3     | integer |           |          |         | (column_name 'c3')
 Server: loopback
 FDW options: (schema_name 'import_source', table_name 'x 6')
 
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 7621f679a99..17a0a1ec8eb 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -6758,12 +6758,17 @@ postgresImportForeignSchema(ImportForeignSchemaStmt *stmt, Oid serverOid)
 
 			/* Add GENERATED if needed */
 			if (import_generated && attgenerated != NULL &&
-				attgenerated[0] == ATTRIBUTE_GENERATED_STORED)
+				(attgenerated[0] == ATTRIBUTE_GENERATED_STORED ||
+				 attgenerated[0] == ATTRIBUTE_GENERATED_VIRTUAL))
 			{
 				Assert(attdefault != NULL);
 				appendStringInfo(&buf,
-								 " GENERATED ALWAYS AS (%s) STORED",
+								 " GENERATED ALWAYS AS (%s)",
 								 attdefault);
+				if (attgenerated[0] == ATTRIBUTE_GENERATED_STORED)
+					appendStringInfoString(&buf, " STORED");
+				else
+					appendStringInfoString(&buf, " VIRTUAL");
 			}
 
 			/* Add NOT NULL if needed */
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 906d76a4ff3..15d8f8dcfd6 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2270,7 +2270,7 @@ select * from rem1;
 create table gloc1 (
   a int,
   b int generated always as (a * 2) stored,
-  c int
+  c int generated always as (a * 3) virtual
 );
 alter table gloc1 set (autovacuum_enabled = 'false');
 create foreign table grem1 (
@@ -3522,7 +3522,7 @@ CREATE TABLE import_source.t3 (c1 timestamptz default now(), c2 typ1);
 CREATE TABLE import_source."x 4" (c1 float8, "C 2" text, c3 varchar(42));
 CREATE TABLE import_source."x 5" (c1 float8);
 ALTER TABLE import_source."x 5" DROP COLUMN c1;
-CREATE TABLE import_source."x 6" (c1 int, c2 int generated always as (c1 * 2) stored);
+CREATE TABLE import_source."x 6" (c1 int, c2 int generated always as (c1 * 2) stored, c3 int generated always as (c1 * 3) virtual);
 CREATE TABLE import_source.t4 (c1 int) PARTITION BY RANGE (c1);
 CREATE TABLE import_source.t4_part PARTITION OF import_source.t4
   FOR VALUES FROM (1) TO (100);
