I use generics a lot in non container/collection scenarios - for example Delphi Mocks fluent api uses the generic type to allow a type safe definition of the mock. Without generics we would be using strings - which is not typesafe and would not survive refactoring.
Another example - I have lexer/parser library (used in FinalBuilder)
//NOTE : T MUST be an Enumerated Type (need better constraints!)
TTokenRec<T> = record
private
.....
end;
ILexer<T> = interface
function Next : TTokenRec<T>;
...
TBaseLexer<T> = class(TInterfacedObject,ILexer<T>)
//concrete usages
TDSLLexer = class(TBaseLexer<TDSLTokenKind>,IDSLLexer)
TVariableSenseLexer = class(TBaseLexer<TTokenKind>)
//parsers built on top of the lexers
IParser<TAstNodeType,TParseErrorType> = interface
TBaseParser<TTokenType,TAstNodeType,TParseErrorType> = class(TInterfacedObject,IParser<TAstNodeType,TParseErrorType>)
TDSLParser = class(TBaseParser<TDSLTokenKind,TDSLASTNodeType,TDSLParserErrorType>)
TVariableSenseParser = class (TBaseParser<TTokenKind, TVariableSenseASTNodeType, TVariableSenseParserErrorType>)
Generics allows you to avoid copying and pasting tons of boilerplate code, changing types etc, or doing having to do tons of nasty type casting.
If Delphi's generics were better there would be many more uses for them, but when you attempt anything complex you run into limitations. If you really want to know what else can be done with generics, you would have to look at other languages that have better generics implementations (like c#).