ジェネリックプログラミングの特徴は、型を抽象化してコードの再利用性を向上させつつ、静的型付け言語の持つ型安全性を維持できることである。ジェネリックプログラミングを用いない場合、例えば伝統的なC言語やPascalのような従来の静的型付け言語において、ソートなどのアルゴリズムや連結リストのようなデータ構造（オブジェクトのコンテナ）を記述する際は、たとえ対象となる要素のデータ型が異なるだけで事実上同一のコードであったとしても、具体的なデータ型ごとにそれぞれ実装しなければならない。整数型のリスト、倍精度浮動小数点数型のリスト、文字列型のリスト、ユーザー定義構造体のリスト、……といった具合である。もしジェネリックプログラミングをサポートしない言語で汎用的なコードを記述して再利用しようと思えば、メモリ空間効率や型安全性などを犠牲にしなければならなくなる（共用体や汎用ポインタ型とキャストを駆使するなど）。一方、C++の関数テンプレートやクラステンプレートのように、ジェネリックプログラミングを用いることで、抽象化された型について一度だけ記述したアルゴリズムやデータ構造をさまざまな具象データ型に適用して、コードを型安全に再利用できるようになる。これがジェネリックプログラミングの利点の一例として挙げられる。以下にC++の例を示す。template<typename T>class LinkedList {public:    // 双方向連結リストのノード。    class Node {        friend class LinkedList;    public:        T value;    private:        Node* prev;        Node* next;    private:        Node() : value(), prev(), next() {}        explicit Node(const T& value, Node* prev = NULL, Node* next = NULL) : value(value), prev(prev), next(next) {}        ~Node() {}    public:        Node* getPrev() { return this->prev; }        Node* getNext() { return this->next; }    };private:    Node dummy;public:    LinkedList() : dummy() {        this->dummy.prev = &this->dummy;        this->dummy.next = &this->dummy;    }    ~LinkedList() { this->clear(); }    size_t getSize() const { /* ... */ }    Node* getHead() { return this->dummy.next; }    Node* getTail() { return this->dummy.prev; }    Node* getSentinel() { return &this->dummy; }    static Node* insertBefore(Node* node, const T& value) {        assert(node);        assert(node->prev);        Node* temp = new Node(value, node->prev, node);        node->prev->next = temp;        node->prev = temp;        return temp;    }    static Node* insertAfter(Node* node, const T& value) {        assert(node);        assert(node->next);        Node* temp = new Node(value, node, node->next);        node->next->prev = temp;        node->next = temp;        return temp;    }    static void remove(Node*& node) {        assert(node);        if (node->prev) { node->prev->next = node->next; }        if (node->next) { node->next->prev = node->prev; }        delete node;        node = NULL;    }    void clear() {        for (Node* current = this->getHead(); current != this->getSentinel(); ) {            Node* temp = current;            current = current->next;            delete temp;        }        this->dummy.prev = &this->dummy;        this->dummy.next = &this->dummy;    }};LinkedList<int> list_of_integers;LinkedList<Animal> list_of_animals;LinkedList<Car> list_of_cars;上記は要素型をTとする双方向連結リストの定義例である。typename Tはテンプレートによる抽象化の対象となる型の名前（プレースホルダー）を表す。そしてこの定義されたクラステンプレートのインスタンス化、すなわち型パラメータTに具象型を与えることによって生成されるクラス型は、Tについて実際に指定した具象型のリストとして扱われる。これらの「T型のコンテナ」を一般にジェネリクス (generics) と呼び、ジェネリックプログラミングの代表的なテクニックである。プログラミング言語によって制約は様々だが、このテクニックは、継承関係やシグネチャといった制約条件 (constraint) を維持する限り、内包するTにあらゆるデータ型を指定可能なクラスの定義を可能にする。これはジェネリックプログラミングの典型であり、一部の言語ではこの形式のみを実装する。ただし、概念としてのジェネリックプログラミングはジェネリクスに限定されない。オブジェクト指向プログラミング言語は、サブタイプ（派生型）でスーパータイプ（基底型）の振る舞い（アルゴリズム）をオーバーライドすることによる動的なポリモーフィズム（多態性）を備えており、動的な多態性もまたスーパータイプによる抽象化とサブタイプによる具象化を実現するものだが、ジェネリクスは静的な多態性による抽象化と具象化を実現するという点で設計を異にする。ジェネリックプログラミングのもう一つの応用例として、型に依存しないスワップ関数の例を示す。template<typename T>void Swap(T& a, T& b) // "&"により参照としてパラメーターを渡している。{    T temp = b;    b = a;    a = temp;}using namespace std;string s1 = "world!", s2 = "Hello, ";Swap(s1, s2);cout << s1 << s2 << endl; // 出力は"Hello, world!"上記の例で使用したC++のtemplate文は、プログラマーや言語の開発者たちにこの概念を普及させたジェネリックプログラミングの例といわれている。この構文はジェネリックプログラミングの全ての概念に対応する。またD言語はC++のテンプレートを基に構文を単純化した完全なジェネリックの機能を提供する。JavaはJ2SE 5.0よりC++の文法に近いジェネリックプログラミングの機能を提供しており、ジェネリクス（「T型のコンテナ」）という、ジェネリックプログラミングの部分集合を実装する。C# 2.0、Visual Basic .NET 2005 (VB 8.0) では、Microsoft .NET Framework 2.0がサポートするジェネリクスを利用するための構文が追加された。MLファミリーはパラメータ多相 (parametric polymorphism) とファンクタと呼ばれるジェネリックモジュールを利用してのジェネリックプログラミングを推奨する。Haskellのタイプクラスのメカニズムもまたジェネリックプログラミングに対応する。Objective-Cにあるような動的型付けを使い、必要に応じて注意深くコーディング規約を守れば、ジェネリックプログラミングの技術を使う必要がなくなる。全てのオブジェクトを包括する汎用型があるためである。Javaもまたそうであるが、キャストが必要なので静的な型付けの統一性を乱してしまう。例えば、ジェネリクスをサポートしていなかった時代のJavaでは、Listのようなコレクションに格納できる要素型はObjectのみであったため、要素取り出しの際には実際のサブクラス型への適切なキャストが必要だった。それに対し、ジェネリクスは静的な型付けについての利点を持ちながら動的な型付けの利点を完全ではないが得られる方法である。