Code review comment: Improve the code a bit:  ```java final TableColumn tableColumn = tableSchema.getTableColumns().get(i); final String fieldName = tableColumn.getName(); final DataType fieldType = tableColumn.getType(); final boolean isGeneratedColumn = tableColumn.isGenerated(); ``` We do know it's safe to call `tableSchema.getTableColumns().get(i)`.

Code under review:
public static TableSchema deriveTableSinkSchema(DescriptorProperties properties) {
		TableSchema.Builder builder = TableSchema.builder();
		TableSchema tableSchema = properties.getTableSchema(SCHEMA);
		for (int i = 0; i < tableSchema.getFieldCount(); i++) {
			TypeInformation t = tableSchema.getFieldTypes()[i];
			String n = tableSchema.getFieldNames()[i];
			Optional<TableColumn> tableColumn = tableSchema.getTableColumn(n);
			boolean isGeneratedColumn = tableColumn.isPresent() && tableColumn.get().isGenerated();
			if (isGeneratedColumn) {
				
				continue;
			}
			boolean isProctime = properties
					.getOptionalBoolean(SCHEMA + "." + i + "." + SCHEMA_PROCTIME)
					.orElse(false);
			String tsType = SCHEMA + "." + i + "." + ROWTIME_TIMESTAMPS_TYPE;
			boolean isRowtime = properties.containsKey(tsType);
			if (!isProctime && !isRowtime) {
				
				String fieldName = properties.getOptionalString(SCHEMA + "." + i + "." + SCHEMA_FROM)
						.orElse(n);
				builder.field(fieldName, t);
			}
			
			else if (isRowtime) {
				switch (properties.getString(tsType)) {
					case ROWTIME_TIMESTAMPS_TYPE_VALUE_FROM_FIELD:
						String field = properties.getString(SCHEMA + "." + i + "." + ROWTIME_TIMESTAMPS_FROM);
						builder.field(field, t);
						break;
					
					
					default:
						throw new TableException(format("Unsupported rowtime type '%s' for sink" +
								" table schema. Currently only '%s' is supported for table sinks.",
								t, ROWTIME_TIMESTAMPS_TYPE_VALUE_FROM_FIELD));
				}
			}
		}

		return builder.build();
	}

Line commented on: boolean isGeneratedColumn = tableColumn.isPresent() && tableColumn.get().isGenerated();

Revised code:
public static TableSchema deriveTableSinkSchema(DescriptorProperties properties) {
		TableSchema.Builder builder = TableSchema.builder();
		TableSchema tableSchema = properties.getTableSchema(SCHEMA);
		for (int i = 0; i < tableSchema.getFieldCount(); i++) {
			final TableColumn tableColumn = tableSchema.getTableColumns().get(i);
			final String fieldName = tableColumn.getName();
			final DataType dataType = tableColumn.getType();
			boolean isGeneratedColumn = tableColumn.isGenerated();
			if (isGeneratedColumn) {
				
				continue;
			}
			boolean isProctime = properties
					.getOptionalBoolean(SCHEMA + "." + i + "." + SCHEMA_PROCTIME)
					.orElse(false);
			String tsType = SCHEMA + "." + i + "." + ROWTIME_TIMESTAMPS_TYPE;
			boolean isRowtime = properties.containsKey(tsType);
			if (!isProctime && !isRowtime) {
				
				String aliasName = properties.getOptionalString(SCHEMA + "." + i + "." + SCHEMA_FROM)
						.orElse(fieldName);
				builder.field(aliasName, dataType);
			}
			
			else if (isRowtime) {
				switch (properties.getString(tsType)) {
					case ROWTIME_TIMESTAMPS_TYPE_VALUE_FROM_FIELD:
						String field = properties.getString(SCHEMA + "." + i + "." + ROWTIME_TIMESTAMPS_FROM);
						builder.field(field, dataType);
						break;
					
					
					default:
						throw new TableException(format("Unsupported rowtime type '%s' for sink" +
								" table schema. Currently only '%s' is supported for table sinks.",
							dataType, ROWTIME_TIMESTAMPS_TYPE_VALUE_FROM_FIELD));
				}
			}
		}

		return builder.build();
	}